home *** CD-ROM | disk | FTP | other *** search
/ PC Format (UK) 124 / pcfcd124-a.iso / Trial Software / BlitzBasic / Rift / Celestial Rift (final).bb next >
Encoding:
Text File  |  2001-04-23  |  108.4 KB  |  2,033 lines

  1. AppTitle "Celestial Rift - Version 1.0 (C)2001 Myke P" ;what this program will be called in MICROSOFT WINDOWS.
  2.  
  3. ;This makes two CONSTants. These are values which will NOT change at any point in the program, so we set their values now.
  4. Const SCREEN_WIDTH = 800
  5. Const SCREEN_HEIGHT = 600
  6. ;This is the code which tells Blitz what Display Resolution to use on the Graphics Card. The "GRAPHICS" command should always be placed before you do
  7. ;*anything* image-related in your program
  8. Graphics SCREEN_WIDTH,SCREEN_HEIGHT,0,1    ;start the graphics mode at SCREEN_WIDTH by SCREEN_HEIGHT, let Blitz choose the depth (,0) and run full screen (,1)
  9.  
  10. ;more program CONSTants..
  11. Const GAME_AREA_X = 50000    ;these two set the size of the map. You *should* keep them the same, 'cos the radar is square
  12. Const GAME_AREA_Y = 50000    ;but technically, you can change the values to anything you like! ;)
  13. ;the following constants are keyboard "SCAN" codes. Every key on the keyboard has a number. You can get the full list in your Blitz manual.
  14. Const KEY_CLOCKWISE = 25    ;(p)    
  15. Const KEY_ANTICWISE = 24    ;(o)
  16. Const KEY_SPEEDUP = 16        ;(q)
  17. Const KEY_SPEEDDOWN = 30    ;(a)
  18. Const KEY_FIRE = 57            ;(Space)
  19. Const KEY_HYPER = 2            ;(1)
  20. Const KEY_BOOST = 50        ;(m)
  21. Const KEY_CLOAK = 46        ;(c)
  22. Const KEY_QUIT = 1            ;(Escape)
  23. Const KEY_PAUSE = 7            ;(Number 6 on the main keyboard)
  24. Const KEY_DEBUG = 59        ;(F1)
  25. Const KEY_SAVESCREEN = 88    ;(F12)
  26. ;the following constants affect the way the game plays. Feel free to mess with the values..
  27. Const INCR_ROTATE# = 5                ;.. but DON'T touch this, otherwise the game will crash (I only drew the animation frames for 5 degree intervals!)
  28. Const INCR_SPEED# = 0.5
  29. Const INCR_SLOW# = 0.125
  30. Const INCR_BOOSTERS_UP# = 0.025
  31. Const INCR_BOOSTERS_DOWN# = .75
  32. Const INCR_CLOAK_UP#= 0.0125
  33. Const INCR_CLOAK_DOWN# = .25 
  34. Const SPEED_MAX = 25
  35. Const SPEED_MIN = -5
  36. Const ENEMY_MAX_DIST = 5000
  37. Const ENEMY_MIN_DIST = 50
  38. Const DAMAGE_ENEMY_BASH = 2
  39. Const DAMAGE_ENEMY_IS_SHOT = 35
  40. Const DAMAGE_PLAYER_BASH = 2
  41. Const DAMAGE_PLAYER_IS_SHOT = 5
  42. Const SCORE_ENEMYCOLLIDE = 50
  43. Const SCORE_ICONCOLLECT = 200
  44. Const SCORE_ENEMY_IS_SHOT = 400
  45. Const SCORE_ENEMY_IS_DESTROYED = 1500
  46. Const BONUS_BOOSTERS = 48
  47. Const BONUS_SHIELD = 48
  48. Const BONUS_CLOAK = 48
  49.  
  50. ;set up changable variables for game/menu (with initial values, if you like - i.e.: you could just as soon as set them later!)
  51. Global FLAG_GAMEON
  52. Global FLAG_MENUON
  53. Global FLAG_PAUSE
  54. Global FLAG_SAVESCREEN = 0
  55. Global FLAG_DEBUG = 0
  56. Global FLAG_GAMESTARTER
  57. Global PLAYER_SHIELD#
  58. Global PLAYER_BOOSTERS#
  59. Global PLAYER_CLOAK#
  60. Global PLAYER_JUMPS
  61. Global PLAYER_SPEED#
  62. Global PLAYER_ANGLE#
  63. Global PLAYER_X#
  64. Global PLAYER_Y#
  65. Global PLAYER_SCORE
  66. Global PLAYER_SCORE_STR$
  67. Global HI_SCORE
  68. Global HI_SCORE_STR$
  69. Global LAST_SCORE
  70. Global LAST_SCORE_STR$
  71. Global SCORE_FILE
  72.  
  73. Global timer
  74. Global frames
  75. Global starson
  76. Global menu_frame
  77. Global menu_accept_quit
  78. Global game_pause_frame
  79. Global game_accept_pause
  80. Global game_pause_stat
  81. Global gameovercounter
  82. Global gameoverstat
  83. Global whichway
  84. Global hypercount#        ;a "#" symbol after the variable name means it can hold a FLOATING POINT number, i.e.: 190.1234
  85. Global pausecount        ;without the "#" symbol, the variable is, by default, an INTEGER (Whole) number, i.e.: 190
  86. Global cloakon#            ;use the symbols when you are *sure* that you want it to hold specific types of data:
  87. Global frame1            ;# - floating point
  88. Global frame2            ;% - integer (whole number)
  89. Global frame3            ;$ - string (text, i.e.: "MYKE 12345"
  90. Global frame4            ;
  91. Global frame5
  92. Global frame6
  93. Global frame7
  94. Global frame8
  95. Global tempstr$
  96.  
  97. timer = CreateTimer(50) ;create a timer set at 50ms (game speed) - play with this to see how you can increase or decrease the speed of the game.
  98.                         ;this should be set at a speed which will look near enough the same on *every* PC it will be played on.
  99.                         ;My PC (a 733MHz PIII with an nVidia GeForce card) will handle upwards of 150 frames per second, quite happily
  100.                         ;but 'lesser' machines will not. 50, therefore, is quite sensible For a game of this nature, who's minimum system spec
  101.                         ;will be something like a PII 300MHz machine (i.e.: Blitz Basic's minimum spec!)
  102.  
  103. ;NOTE: there's no need to organise your variable declarations, as I have here, into sections. They can appear in any order you like, before the main program begins.
  104. ;I just do this, 'cos it looks right professional! :))))
  105.  
  106. ;picture/animation (and related) variables
  107. Dim game_stars(5)            ;these 3 are ARRAYS. An array is automatically Global, but requires the Keyword (Yellow bit) DIM instead. This means "Dimension".
  108. Dim game_icons(4)            ;the arrays have single dimensions (imagine one straight line of boxes, each that can contain a single variable) 0 to.. (the number in brackets)
  109. Dim game_jumps_level(5)        ;in the case of "game_jumps_level", it has *SIX* containers: 0, 1, 2, 3, 4, 5 and 6.
  110. Global game_background
  111. Global game_radar
  112. Global game_shields
  113. Global game_jumps
  114. Global game_boosters
  115. Global game_cloak
  116. Global game_shields_level
  117. Global game_boosters_level
  118. Global game_cloak_level
  119. Global game_levels
  120. Global game_score
  121. Global game_hiscore
  122. Global game_icon_dot
  123. Global game_player
  124. Global game_player_frame
  125. Global game_player_dot
  126. Global game_enemy1
  127. Global game_enemy1_dot
  128. Global game_scorefont
  129. Global game_bullet_player
  130. Global game_bullet_enemy1
  131. Global game_explosion
  132. Global player_explosion_frame#
  133. Global game_gameover
  134. Global game_paused
  135. Global menu_hiscore
  136. Global menu_lastscore
  137. Global menu_scorefont
  138. Global menu_start
  139. Global menu_start_stat
  140. Global menu_logo
  141. Global menu_credit
  142. Global menu_guildhall
  143. Global menu_thanks
  144. Global menu_quit
  145. Global menu_ship1
  146. Global menu_ship2
  147. Global menu_ship_hor
  148. Global menu_ship_ver#
  149. Global menu_ship_type
  150.  
  151. ;sounds (and related) variables
  152. Global sound_explosion1
  153. Global sound_explosion2
  154. Global sound_explosion_channel
  155. Global sound_icon
  156. Global sound_icon_channel
  157. Global sound_boosters
  158. Global sound_boosters_channel
  159. Global sound_enemy_laser
  160. Global sound_enemy_laser_channel
  161. Global sound_player_laser
  162. Global sound_player_laser_channel
  163. Global sound_hyperjump
  164. Global sound_hyperjump_channel
  165. Global sound_collision
  166. Global sound_collision_channel
  167. Global sound_cloak
  168. Global sound_cloak_channel
  169. Global sound_bullethit1
  170. Global sound_bullethit2
  171. Global sound_bullethit_channel
  172. Global music_menu
  173. Global music_menu_level#
  174. Global music_game
  175. Global music_game_level#
  176.  
  177. ;Types are like Structures in C. You have a "Type" called whatever. Then you can make multiple versions of the type. Each version of the Type has the same properties, i.e.:
  178. ;a FISH (the Type) has EYES, MOUTH, SCALES And FINS (it's properties) - ALL FISH have these properties.
  179. ;a DOG (the Type) has EYES, MOUTH, FUR and TAIL (it's properties) - ALL DOGS have these properties (look like this.)
  180. Type stars                        ;create "Type" for parallex stars
  181.     Field depth,x#,y#            ;each star has a depth, x and y position and a picture
  182. End Type
  183.  
  184. Type enemies                    ;same for enemies
  185.     Field x#,y#,energy,angle,speed#,style,maxspeed,dest_angle,dist_travelled,dist_to_go,dest_opp#,dest_hyp#,dest_adj#,rotate_angle,status,bulletlimiter,exp_frame#,gen
  186. End Type
  187. ;notice the "enemies" Type has a "style"?
  188. ;originally, I planned to have different styles of enemy space-ships, but never got around to drawing the graphics!
  189. ;the "style" is used in the subsequent code, and the Type property remains, so *technically* adding new enemy styles to the game should be pretty easy! :)
  190.  
  191. Type icons                        ;same for icons
  192.     Field x#,y#,style,frame#
  193. End Type
  194.  
  195. ;this is for the bullets. I've used an array, rather than a type (which would have been just as good in this case) to show you how MULTIDIMENSIONAL arrays can work.
  196. Const bulletnum = 500
  197. Global bulletlimiter
  198. Global nextbullet = 0
  199. Dim bullets(bulletnum-1,7) ;create an array for 'bulletnum' (0 to bulletnum -1) on-screen bullets with 8 values per bullet:
  200.                         ;0 = bullet_x, 1 = bullet_y, 2 = bullet_angle, 3 = bullet_speed,
  201.                         ;4 = bullet_style, 5 = bullet_animframe, 6 = bullet_origin_x, 7 = bullet_origin_y
  202.                         ;we'll say that a bullet's style can also say whether or not it's in use, i.e.: 0 = off, 1 = player, 2 = enemy1
  203.  
  204. ;load in the sounds (credit given for .WAV source)
  205. sound_icon = LoadSound("SndRes/icon.wav")                    ;Mark Rayson
  206. sound_enemy_laser = LoadSound("SndRes/enemy-laser.wav")        ;Mark Rayson
  207. sound_hyperjump = LoadSound("SndRes/hyperjump.wav")            ;Mark Rayson
  208. SoundPitch sound_hyperjump,32000    ;Mark's sample lasted a bit too long in it's original format (22000 Hz), so increasing the Pitch to 32000 Hz makes the sample play faster (and audibly higher too)
  209. sound_collision = LoadSound("SndRes/collision.wav")            ;Mark Rayson
  210. sound_explosion1 = LoadSound("SndRes/explosion1.wav")         ;WAV Central (www.wavcentral.com)
  211. sound_explosion2 = LoadSound("SndRes/explosion2.wav")         ;WAV Central (www.wavcentral.com)
  212. sound_boosters = LoadSound("SndRes/boosters.wav")            ;WAV Central (www.wavcentral.com)
  213. sound_player_laser = LoadSound("SndRes/player-laser.wav")    ;WAV Central (www.wavcentral.com)
  214. sound_cloak = LoadSound("SndRes/cloak.wav")                    ;WAV Central (www.wavcentral.com)
  215. sound_bullethit1 = LoadSound("SndRes/bullethit1.wav")        ;EarthStation1 (www.earthstation1.com)
  216. sound_bullethit2 = LoadSound("SndRes/bullethit2.wav")        ;EarthStation1 (www.earthstation1.com)
  217.  
  218.  
  219. ;This peice of code reads a file called "rift.dat" for the HI_SCORE and LAST_SCORE values from the last session
  220. SCORE_FILE = ReadFile("rift.dat")    ;use the variable SCORE_FILE (similar to image numbers before) as a reference to the file
  221.                                     ;open a file for READING ("ReadFile"). The file is called "Rift.dat"
  222. If SCORE_FILE = 0 Then                ;if the file wasn't found, then the reference "SCORE_FILE" will have been set to 0
  223.     HI_SCORE = 0
  224.     LAST_SCORE = 0
  225. Else                                ;if the file wasn't found, then the reference "SCORE_FILE" will have been set to something *other* than 0.
  226.     HI_SCORE = Int(ReadLine(SCORE_FILE))    ;read in one line from the file, then make it equal a number, rather than the ASCII string it is stored as. The first line becomes the HI_SCORE
  227.     LAST_SCORE = Int(ReadLine(SCORE_FILE))  ;read in another line from the file. This is the LAST_SCORE.
  228. End If
  229. CloseFile(SCORE_FILE)                ;we've finished with the file, so CLOSE it (tells Blitz to disregard the reference number) - we won't be READing from it anymore!
  230.  
  231. ;This section turns the Integer HI_SCORE and LAST_SCORE values into strings with leading 0's
  232. ;i.e.: 1000 becomes "0001000". You will see this exact same peice of code later on, so - professionally - it *should* have been done in a FUNCTION.
  233. ;I've kept it separate to show that you *can* just as well use copied code and not see a difference in the final program.
  234. If HI_SCORE < 10 Then                                    ;If the value of HI_SCORE is less than 10, then..
  235.     HI_SCORE_STR = "000000"+Str(HI_SCORE)                ;make the string "HI_SCORE_STR" = "000000" and put the value of HI_SCORE on the end as a string
  236.                                                         ;such that, for example, HI_SCORE_STR now holds the text: "0000003"
  237.                                                         
  238. ElseIf HI_SCORE >=10 And HI_SCORE < 100 Then            ;If the value of HI_SCORE is 10 or more, AND the value of HI_SCORE is less than 100, then..
  239.     HI_SCORE_STR = "00000"+Str(HI_SCORE)                ;.. and so on.. the use of "AND" here means that both 'arguements' (the HI_SCORE >= 10 type bits)
  240.                                                         ;must be true, or the resulting operation (the HI_SCORE_STR = ... type bit) won't happen.
  241.                                                         ;In this case, for example, 104 *is* "10 or more" but it *is not* less than 100, so ignore this "If statement"
  242.                                                         ;The "ElseIf" keyword means that if the first "IF" didn't fire, then "try this one"..
  243. ElseIf HI_SCORE >=100 And HI_SCORE < 1000 Then
  244.     HI_SCORE_STR = "0000"+Str(HI_SCORE)
  245. ElseIf HI_SCORE >=1000 And HI_SCORE < 10000 Then
  246.     HI_SCORE_STR = "000"+Str(HI_SCORE)
  247. ElseIf HI_SCORE >=10000 And HI_SCORE < 100000 Then
  248.     HI_SCORE_STR = "00"+Str(HI_SCORE)
  249. ElseIf HI_SCORE >=100000 And HI_SCORE < 1000000 Then
  250.     HI_SCORE_STR = "0"+Str(HI_SCORE)
  251. ElseIf HI_SCORE >=100000 And HI_SCORE < 10000000 Then
  252.     HI_SCORE_STR = Str(HI_SCORE)
  253. Else                                                    ;The "Else" keyword means that if NONE of the other IF statements fired, then do this next bit, as a last resort!
  254.                                                         ;The "Else" statement always comes last in an "IF.. ELSEIF.. ENDIF" peice of code
  255.     HI_SCORE_STR = "9999999"
  256. End If                                                    ;The "EndIf" keyword means that's the end of this set of checks.
  257.  
  258. If LAST_SCORE < 10 Then                                        ;Starting a new "IF.. ELSEIF.. ENDIF" peice of code, rather than using more "ElseIf"s means that this
  259.     LAST_SCORE_STR = "000000"+Str(LAST_SCORE)                ;set of decisions is not affected by the previous set.
  260. ElseIf LAST_SCORE >=10 And LAST_SCORE < 100 Then
  261.     LAST_SCORE_STR = "00000"+Str(LAST_SCORE)
  262. ElseIf LAST_SCORE >=100 And LAST_SCORE < 1000 Then
  263.     LAST_SCORE_STR = "0000"+Str(LAST_SCORE)
  264. ElseIf LAST_SCORE >=1000 And LAST_SCORE < 10000 Then
  265.     LAST_SCORE_STR = "000"+Str(LAST_SCORE)
  266. ElseIf LAST_SCORE >=10000 And LAST_SCORE < 100000 Then
  267.     LAST_SCORE_STR = "00"+Str(LAST_SCORE)
  268. ElseIf LAST_SCORE >=100000 And LAST_SCORE < 1000000 Then
  269.     LAST_SCORE_STR = "0"+Str(LAST_SCORE)
  270. ElseIf LAST_SCORE >=100000 And LAST_SCORE < 10000000 Then
  271.     LAST_SCORE_STR = Str(LAST_SCORE)
  272. Else
  273.     LAST_SCORE_STR = "9999999"
  274. End If
  275.  
  276. ;this code makes 4 'objects' in a "Type" called "ICONS".
  277. For i = 1 To 4                    ;do this 1, 2, 3, 4 times
  278.     icon.icons = New icons        ;create a new icon
  279.     icon\style = i                ;the icon style for each new icon is equal to the increment of i (i.e.: 1, 2, 3 or 4!)
  280.     icon\frame = Int(Rnd(0,5))    ;create a random frame number between 0 and 5 for each new icon
  281. Next
  282.  
  283. menustars = SCREEN_HEIGHT/3 ;generate a number of stars, so that they look dense enough on all test resolutions
  284. starson = 1 ;tells the program to show the stars (see later)
  285. For i=0 To menustars                    ;create <menustars> number of stars in the STARS type
  286.     star.stars=New stars                ;add a new star for each increment of i
  287. Next
  288.  
  289. For i = 1 To 10
  290.     enemy.enemies = New enemies ;make 10 enemies (we'll set their variables later)
  291. Next
  292.  
  293. ;this code loads the image numbers into an array called "game_ stars", which we DIMmed earlier. It has 6 containers (0,1,2,3,4,5) but I'm only using 1 to 5!
  294. ;an "image number" is what Blitz uses to reference graphics held in the Video Memory, i.e.:
  295. ;1. Image number 12 is a picture of a flower.
  296. ;2. Make a variable called "flower_pic" = 12
  297. ;3. Wherever Blitz is told to draw "flower_pic", reference image number 12 in the Video Memory.
  298. game_stars(1) = LoadImage("GfxRes/backg-star-1.bmp")    ;container (1) in "game_stars" holds the image number for this picture ("GfxRes/backg-star-1.bmp")
  299. game_stars(2) = LoadImage("GfxRes/backg-star-2.bmp")    ;etc..
  300. game_stars(3) = LoadImage("GfxRes/backg-star-3.bmp")
  301. game_stars(4) = LoadImage("GfxRes/backg-star-4.bmp")
  302. game_stars(5) = LoadImage("GfxRes/backg-star-5.bmp")
  303. For i = 1 To 5
  304.     MaskImage game_stars(i),255,0,255    ;mask the images for each star, so that MAGENTA (255,0,255) is the transparent colour
  305. Next
  306.  
  307. ;similarly, this code loads the image numbers into an array called "game_icons"
  308. ;however, these are images that contain the frames of an Animation, so a different Load command is used.
  309. game_icons(1) = LoadAnimImage("GfxRes/icon-boost.bmp",32,32,0,6)    ;LoadAnimImage has the same structure as LoadImage, with additional numbers after the picture filename
  310. game_icons(2) = LoadAnimImage("GfxRes/icon-shield.bmp",32,32,0,6)    ;these are: Frame Width (pixels), Frame Height (pixels), Starting Framenumber (usually 0)
  311. game_icons(3) = LoadAnimImage("GfxRes/icon-cloak.bmp",32,32,0,6)    ;and the Number of Frames in the Image (as *you* would count them (in this case 6)
  312. game_icons(4) = LoadAnimImage("GfxRes/icon-jump.bmp",32,32,0,6)        ;have a look at the file "icon-boost" in Paint Shop Pro and see for yourself the 6 frames of animation.
  313. For i = 1 To 4
  314.     MaskImage game_icons(i),255,0,255    ;mask the images for each icon, so that MAGENTA (255,0,255) is the transparent colour
  315. Next
  316.  
  317. game_jumps_level(1) = LoadImage("GfxRes/game-jumps-level1.bmp")
  318. game_jumps_level(2) = LoadImage("GfxRes/game-jumps-level2.bmp")
  319. game_jumps_level(3) = LoadImage("GfxRes/game-jumps-level3.bmp")
  320. game_jumps_level(4) = LoadImage("GfxRes/game-jumps-level4.bmp")
  321. game_jumps_level(5) = LoadImage("GfxRes/game-jumps-level5.bmp")
  322. For i = 1 To 5
  323.     MaskImage game_jumps_level(i),255,0,255    ;mask the images for each level block, so that MAGENTA (255,0,255) is the transparent colour
  324. Next
  325.  
  326. ;notice in the following code, we're loading (and MASKING) graphics in exactly the same way as before, but into regular variables instead of arrays.
  327. ;this next bit is all animations
  328. game_player = LoadAnimImage("GfxRes/player-ship.bmp",80,80,0,72) ;load in the 'sprite' for the player ship
  329. MaskImage game_player,255,0,255 ;mask the images for the player ship, so that MAGENTA (255,0,255) is the transparent colour
  330. game_enemy1 = LoadAnimImage("GfxRes/enemy1-ship.bmp",64,64,0,72) ;load in the 'sprite' for the enemy ship (type 1)
  331. MaskImage game_enemy1,255,0,255 ;mask the images for the enemy ship (type 1), so that MAGENTA (255,0,255) is the transparent colour
  332. game_bullet_player = LoadAnimImage("GfxRes/bullet-player.bmp",10,10,0,6)    ; the blue player bullet animation
  333. MaskImage game_bullet_player,255,0,255 ;mask the images
  334. game_bullet_enemy1 = LoadAnimImage("GfxRes/bullet-enemy1.bmp",10,10,0,6)    ; the orange enemy bullet animation
  335. MaskImage game_bullet_enemy1,255,0,255 ;mask the images
  336. game_explosion = LoadAnimImage("GfxRes/game-explosion.bmp",100,100,0,25)    ; the explosion, as done by Lennart's MkExpl 3.0
  337. MaskImage game_explosion,255,0,255 ;mask the images
  338. game_scorefont = LoadAnimImage("GfxRes/game-scorefont.bmp",18,14,0,11)        ; the score font used in the game
  339. MaskImage game_scorefont,255,0,255 ;mask the images
  340. menu_scorefont = LoadAnimImage("GfxRes/menu-scorefont.bmp",18,14,0,11)        ; the score font used on the menu
  341. MaskImage menu_scorefont,255,0,255 ;mask the images
  342. ;these are all plain single-frame pictures
  343. ;menu piccies
  344. menu_logo = LoadImage("GfxRes/menu-logo.bmp")            ;the CELESTIAL RIFT logo
  345. menu_ship1 = LoadImage("GfxRes/menu-ship1.bmp")            ;the big player-type ship
  346. menu_ship2 = LoadImage("GfxRes/menu-ship2.bmp")            ;the big enemy type ship
  347. menu_guildhall = LoadImage("GfxRes/menu-guildhall.bmp")    ;the GUILDHALL message at the top
  348. menu_thanks = LoadImage("GfxRes/menu-thanks.bmp")        ;the THANKS message at the bottom
  349. menu_credit = LoadImage("GfxRes/menu-credit.bmp")        ;the CREDITS message below the logo
  350. menu_start = LoadImage("GfxRes/menu-start.bmp")            ;the "PRESS FIRE TO START" caption
  351. menu_quit = LoadImage("GfxRes/menu-quit.bmp")            ;the "(ESCAPE TO QUIT)" caption
  352. menu_hiscore = LoadImage("GfxRes/menu-hiscore.bmp")        ;the "HI SCORE" caption
  353. menu_lastscore = LoadImage("GfxRes/menu-lastscore.bmp")    ;the "LAST SCORE" caption
  354. ;game piccies
  355. game_background = LoadImage("GfxRes/game-bg.bmp")             ;the sexy blue background behind the stars
  356. game_radar = LoadImage("GfxRes/game-radar.bmp")                ;the radar box
  357. game_shields = LoadImage("GfxRes/game-shields.bmp")            ;the shields box
  358. game_jumps = LoadImage("GfxRes/game-jumps.bmp")                ;the jumps box
  359. game_cloak = LoadImage("GfxRes/game-cloak.bmp")                ;the cloak box
  360. game_boosters = LoadImage("GfxRes/game-boosters.bmp")        ;go on.. guess.. it's the boosters box
  361. game_levels = LoadImage("GfxRes/game-levels.bmp")            ;this is the big RED-to-GREEN bar used on the cloak, shields and booster's boxes.
  362. game_score = LoadImage("GfxRes/game-score.bmp")                ;the score box
  363. game_hiscore = LoadImage("GfxRes/game-hiscore.bmp")            ;the hi score box
  364. game_gameover = LoadImage("GfxRes/game-gameover.bmp")        ;the game over logo, which I tend to see a lot of.. :(
  365. game_paused = LoadImage("GfxRes/game-paused.bmp")            ;the paused logo
  366. game_player_dot = LoadImage("GfxRes/player-radardot.bmp")    ;radar dots for the player, enemy and bonus icons respectively
  367. game_enemy1_dot = LoadImage("GfxRes/enemy1-radardot.bmp")
  368. game_icon_dot = LoadImage("GfxRes/icon-radardot.bmp")
  369. MaskImage menu_ship1,255,0,255            ;mask all the images.
  370. MaskImage menu_ship2,255,0,255            ;notice that it doesn't matter what order you do the masks in!
  371. MaskImage menu_credit,255,0,255
  372. MaskImage menu_guildhall,255,0,255        ;by the way, if when testing your program, you get the error message "IMAGE DOES NOT EXIST" at this point
  373. MaskImage menu_thanks,255,0,255            ;in the program, it's because the LOADIMAGE command above didn't find the file properly.
  374. MaskImage menu_start,255,0,255            ;This is usually either because; 1 - You've typed the wrong filename in the LOADIMAGE bit, or
  375. MaskImage menu_quit,255,0,255            ;2 - You've got the variable name wrong in the MASKIMAGE bit.
  376. MaskImage menu_hiscore,255,0,255
  377. MaskImage menu_lastscore,255,0,255        ;you could perform some checks at the end of loading all the images, so that you know they've all been loaded
  378. MaskImage game_radar,255,0,255            ;successfully. If they haven't then you could end the program properly and tell the user that they've got
  379. MaskImage game_shields,255,0,255        ;corrupt or missing files!
  380. MaskImage game_jumps,255,0,255
  381. MaskImage game_cloak,255,0,255            ;as you'll see, I haven't bothered! :)
  382. MaskImage game_boosters,255,0,255
  383. MaskImage game_score,255,0,255
  384. MaskImage game_hiscore,255,0,255
  385. MaskImage game_background,255,0,255
  386. MaskImage game_gameover,255,0,255
  387. MaskImage game_paused,255,0,255
  388. MaskImage game_levels,255,0,255
  389.  
  390. ;Right! That's it, we've set up *everything* we're going to need from outside the program.
  391. menu_loop() ;start the proper program loop by 'calling' the function called "menu_loop()" - which, conveniently, is just coming up!!!
  392.  
  393. ;this function keeps the menu loop going.. It starts playing tunes and sets a couple of variables. 
  394. ;Then it goes into a never ending loop which carries out a sequence of checks and function calls.
  395. Function menu_loop() ;Start of the Function whose name is "menu_loop()"
  396.     FLAG_MENUON = 1 ;tells the program that the menu is running, for use in the REPEAT..FOREVER statement in a sec..
  397.     music_menu = PlayMusic("SndRes/Danube.mid")    ;start playing the music file "Danube.mid" (found in the SndRes folder) on channel "music_menu"
  398.     menu_ship_hor = (SCREEN_WIDTH/2)-(ImageWidth(menu_ship1)/2) ;this sets the starting horizontal position of the big ship on the menu
  399.     menu_ship_ver = SCREEN_HEIGHT+1    ;this sets the vertical starting position of the big ship on the menu at one pixel off the bottom of the screen.
  400.                                     ;notice that images are (by default) handled from the TOP-LEFT pixel, so, horizontally, I offset the value
  401.                                     ;to the left, by half the width of the ship image.
  402.     menu_ship_type = 1                ;set up some initial values for these counters
  403.     menu_frame = 1                    
  404.     menu_start_stat = 0
  405.     menu_accept_quit = 0
  406.     
  407.     music_menu_level = 1    ;this value will be used to set the volume of the music track in a minute..
  408.     Repeat        ;a REPEAT.. FOREVER loop will carry out the code in between for as long as the program is running..
  409.         If FLAG_MENUON = 1 Then    ;If the FLAG_MENUON flag is set to 1 then "do" the following..
  410.             menu_loop_update()    ;call function "menu_loop_update()"
  411.             ;this IF statement checks to see if the game music is playing (as it will be when you quit the game)
  412.             If ChannelPlaying(music_game) = True Then        ;if it is, then..
  413.                 music_game_level = music_game_level -.01    ;decrease the value of this variable by .01
  414.                 ChannelVolume music_game, music_game_level    ;set the volume of this channel "music_game" to the value of music_game_level
  415.                 If music_game_level <= 0 Then                ;if the value of "music_game_level" is 0 or less, then
  416.                     StopChannel(music_game)                    ;stop the sounds playing on channel "music_game"
  417.                 End If                                        ;notice I've used an IF statement inside of another IF statement.. You'll be doing this a lot, it's called "Nesting"
  418.             End If
  419.         Else                                    ;if the FLAG_MENUON flag wasn't set to 1 then "do" the following..
  420.             SCORE_FILE = WriteFile("rift.dat")        ;Open file "rift.dat" for WRITing (using the variable "SCORE_FILE" as a reference number
  421.             WriteLine SCORE_FILE,Str(HI_SCORE)        ;Write the value of HI_SCORE (as a STRing) into the file
  422.             WriteLine SCORE_FILE,Str(LAST_SCORE)    ;Write the value of LAST_SCORE (as a STRing) into the file
  423.             CloseFile(SCORE_FILE)                    ;Close the file, as we've finished with it
  424.             End                                        ;END the program
  425.         End If
  426.         If ChannelPlaying(music_menu) = False Then            ;checks to see if the menu music has finished playing on channel "music_menu", if so, restart it!
  427.             music_menu = PlayMusic("SndRes/Danube.mid")
  428.         End If
  429.     Forever    ;end of the REPEAT.. FOREVER loop
  430. End Function ;End of the function
  431.  
  432. ;"menu_loop_update()" checks for key-presses, alters position coordinates on the screen
  433. ;and various variables/flags for use in "menu_draw_update()" and the game functions too.
  434. ;in fact, you'll see that this has the same organisational structure as the proper game loop (albeit much less complex!)
  435. Function menu_loop_update()
  436.     frames = WaitTimer(timer) ;returns a value to "frames" for how many video screen refreshes (The MHz of your monitor) occured since the last call to our timer
  437.     For i = 1 To frames    ;update the screen positions for "frames" number of changes.. This enables drawing frames to be skipped on slower machines.
  438.         If KeyDown(KEY_QUIT)                ;If the user presses the "QUIT" button on the keyboard, then..
  439.             FlushKeys                        ;(when using SCAN CODES, flush the keyboard buffer after each successful "Have they pressed a particular key" question.)
  440.  
  441.             If menu_accept_quit = 1 Then    ;If the variable "menu_accept_quit" is 1, then set the FLAG_MENUON to 0.
  442.                 FLAG_MENUON = 0                ;back in the "menu_loop()" function, this will cause the program to end!
  443.             End If
  444.         End If
  445.  
  446.         If KeyDown(KEY_FIRE)                ;If the user presses the "FIRE" button on the keyboard, then..
  447.             FlushKeys
  448.             FLAG_DEBUG = 0                    
  449.             FLAG_GAMESTARTER = 1
  450.             hypercount = 102
  451.             FLAG_PAUSE = 0
  452.             game_loop()                            ;call the function called "game_loop()" (the game will run, but once it has ended, we'll find ourselves back here...)
  453.             
  454.             menu_ship_ver = SCREEN_HEIGHT+1
  455.             menu_frame = 1
  456.             menu_start_stat = 0
  457.             menu_accept_quit = 0                ;by setting this to 0, we'll stop the program ending by any surplus "QUIT" keystrokes carrying over from the game, by
  458.                                                 ;using the menu_frame counter at the end of this FOR loop.
  459.             FLAG_PAUSE = 0
  460.             If PLAYER_SCORE > HI_SCORE Then        ;checks to see if the PLAYER_SCORE from the last game is higher than the currently held "HI SCORE", if it is, then
  461.                 HI_SCORE = PLAYER_SCORE            ;that PLAYER_SCORE becomes the new HI SCORE!
  462.             End If
  463.             LAST_SCORE = PLAYER_SCORE            ;the LAST SCORE is always set to the PLAYER SCORE from the last game! :)
  464.             FlushKeys
  465.         End If
  466.         If KeyDown(KEY_DEBUG)                ;if the user presses the "DEBUG" button on the keyboard, then..
  467.             FlushKeys
  468.             FLAG_DEBUG = 1                        ;this is all exactly the same as "FIRE" above, but now FLAG_DEBUG is set to 1.
  469.             FLAG_GAMESTARTER = 1                ;later on, you'll see that we use this to turn on, or off, some overlayed displays in the game loop!
  470.             hypercount = 102
  471.             FLAG_PAUSE = 0
  472.             game_loop()
  473.             menu_ship_ver = SCREEN_HEIGHT+1
  474.             menu_frame = 1
  475.             menu_start_stat = 0
  476.             menu_accept_quit = 0
  477.             FLAG_PAUSE = 0
  478.             If PLAYER_SCORE > HI_SCORE Then
  479.                 HI_SCORE = PLAYER_SCORE    
  480.             End If
  481.             LAST_SCORE = PLAYER_SCORE    
  482.             FlushKeys
  483.         End If            
  484.         If KeyDown(KEY_SAVESCREEN)            ;if the user presses the "SAVESCREEN" button on the keyboard, then..
  485.             FlushKeys
  486.             FLAG_SAVESCREEN = 1                    ;just sets FLAG_SAVESCREEN to 1. You'll see this used in the next function.
  487.         End If
  488.         If menu_ship_ver > (-50 - ImageHeight(menu_ship1)) ;if the bottom of the (largest) ship picture gets to 50 pixels above the top of the screen
  489.             Select menu_ship_type    ;A SELECT..CASE statement is like an IF statement, but only performs 1 check, i.e.: "What is the value of I?"
  490.                 Case 1    ;if "menu_ship_type" is 1 then..
  491.                     menu_ship_ver = menu_ship_ver - .3 ;how fast menuship1 moves up the screen
  492.                 Case 2    ;if "menu_ship_type" is 1 then..
  493.                     menu_ship_ver = menu_ship_ver - .8 ;how fast menuship2 moves up the screen
  494.             End Select
  495.         Else
  496.             menu_ship_ver = SCREEN_HEIGHT+1    ;reset the vertical position so that the top of the ship is at the bottom of the screen
  497.             menu_ship_hor = Rnd(0,SCREEN_WIDTH-ImageWidth(menu_ship1)) ;create a random horizontal position
  498.             menu_ship_type = Int(Rnd(1,2)) ;randomly choose between values 1 or 2
  499.         End If
  500.         menu_frame = menu_frame + 1        ;increase the value of "menu_frame" by 1
  501.         If menu_frame = 25 Then            ;if the value of "menu_frame" gets to 25 then reset it to 1
  502.             menu_frame = 1
  503.             menu_accept_quit = 1            ;now we've turned the user's ability to press the "QUIT" button back on (see the IF statement in the KeyDown(KEY_QUIT) statement above!
  504.             If menu_start_stat = 1 Then    ;this bit just switches the value of "menu_start_stat" between 1 and 0, i.e. :If it's 1, then make it 0, if it's 0, then make it 1 etc.
  505.                 menu_start_stat = 0        ;this will be used in the next function to flash the "PRESS FIRE TO START" caption on and off!
  506.             Else
  507.                 menu_start_stat = 1
  508.             End If
  509.         End If
  510.     Next
  511.     If HI_SCORE < 10 Then                                        ;remember this from before? I was saying it could've been done in a function?
  512.         HI_SCORE_STR = "000000"+Str(HI_SCORE)                    ;exactly the same code.. (just converts the number 103 to the string "0000103")
  513.     ElseIf HI_SCORE >=10 And HI_SCORE < 100 Then
  514.         HI_SCORE_STR = "00000"+Str(HI_SCORE)
  515.     ElseIf HI_SCORE >=100 And HI_SCORE < 1000 Then
  516.         HI_SCORE_STR = "0000"+Str(HI_SCORE)
  517.     ElseIf HI_SCORE >=1000 And HI_SCORE < 10000 Then
  518.         HI_SCORE_STR = "000"+Str(HI_SCORE)
  519.     ElseIf HI_SCORE >=10000 And HI_SCORE < 100000 Then
  520.         HI_SCORE_STR = "00"+Str(HI_SCORE)
  521.     ElseIf HI_SCORE >=100000 And HI_SCORE < 1000000 Then
  522.         HI_SCORE_STR = "0"+Str(HI_SCORE)
  523.     ElseIf HI_SCORE >=100000 And HI_SCORE < 10000000 Then
  524.         HI_SCORE_STR = Str(HI_SCORE)
  525.     Else
  526.         HI_SCORE_STR = "9999999"
  527.     End If
  528.     If LAST_SCORE < 10 Then
  529.         LAST_SCORE_STR = "000000"+Str(LAST_SCORE)
  530.     ElseIf LAST_SCORE >=10 And LAST_SCORE < 100 Then
  531.         LAST_SCORE_STR = "00000"+Str(LAST_SCORE)
  532.     ElseIf LAST_SCORE >=100 And LAST_SCORE < 1000 Then
  533.         LAST_SCORE_STR = "0000"+Str(LAST_SCORE)
  534.     ElseIf LAST_SCORE >=1000 And LAST_SCORE < 10000 Then
  535.         LAST_SCORE_STR = "000"+Str(LAST_SCORE)
  536.     ElseIf LAST_SCORE >=10000 And LAST_SCORE < 100000 Then
  537.         LAST_SCORE_STR = "00"+Str(LAST_SCORE)
  538.     ElseIf LAST_SCORE >=100000 And LAST_SCORE < 1000000 Then
  539.         LAST_SCORE_STR = "0"+Str(LAST_SCORE)
  540.     ElseIf LAST_SCORE >=100000 And LAST_SCORE < 10000000 Then
  541.         LAST_SCORE_STR = Str(LAST_SCORE)
  542.     Else
  543.         LAST_SCORE_STR = "9999999"
  544.     End If
  545.     menu_draw_update() ;call the function "menu_draw_update" which draws all these new things on the screen
  546. End Function
  547.  
  548. ;"menu_draw_update()" just draws things on your monitor, using values set and altered in the last function (menu_loop_update).
  549. Function menu_draw_update()
  550.     SetBuffer BackBuffer()    ;draw all of the following to the backbuffer() which is an area video memory which is not shown on screen.
  551.                             ;the idea is that you draw everything here, then SHOW it to the user when the full picture is complete.
  552.                             
  553.     ClsColor 0,0,0        ;changes the CLearScreen colour to black (0,0,0)
  554.                         ;Color commands use the 3 parameters as RED value, GREEN value, BLUE value
  555.                         ;which is how pixel colours are made up on the monitor. If you're familiar with
  556.                         ;any PC Paint Packages, you'll probably be quite familiar with this.
  557.     Cls                    ;CLears the Screen
  558.     
  559.     ;this next section draws all of the pictures on to the backbuffer() at the specified coordinates.
  560.     ;notice that the pictures are drawn in sequence, with the backmost things drawn first and the foremost things drawn last
  561.     ;kind of like making a collage!
  562.     DrawImage menu_logo,(SCREEN_WIDTH/2)-(ImageWidth(menu_logo)/2),0    ;this draws the menu_logo image at "x","y"
  563.                         ;I've used EQUATIONS to make up x and y for all the images in this project, so that when you change
  564.                         ;the resolution values (back at the beginning of the code) everything still appears at the correct position
  565.                         ;on the screen. If you know what resolution you'll be working at, then you can quite happily put x and y as
  566.                         ;ordinary numbers in here.
  567.                         ;For example, at 800*600, the menu_logo image will be drawn at:
  568.                         ;SCREEN_WIDTH = 800
  569.                         ;800/2 = 400
  570.                         ;ImageWidth(menu_logo) is the width (in pixels) of this particular image (which is 547 pixels)
  571.                         ;547/2 = 273.5
  572.                         ;(800 - 273.5 = 126.5)
  573.                         ;So, menu_logo would be drawn at 127,0 (because Blitz requires whole number coordinates, it will automatically
  574.                         ;round up 126.5 to be 127.)
  575.     DrawImage menu_guildhall,(SCREEN_WIDTH/2)-(ImageWidth(menu_guildhall)/2),5
  576.     DrawImage menu_credit,(SCREEN_WIDTH/2)-(ImageWidth(menu_credit)/2),200
  577.     DrawImage menu_quit,(SCREEN_WIDTH/2)-(ImageWidth(menu_quit)/2),SCREEN_HEIGHT-75
  578.     DrawImage menu_hiscore,10,SCREEN_HEIGHT-45
  579.     DrawImage menu_lastscore,(SCREEN_WIDTH)-282,SCREEN_HEIGHT-45
  580.  
  581.     ;this next bit builds each number in the HI_SCORE_STR and LAST_SCORE_STR out of the pictures in the score font
  582.     For i = 1 To 7    ;there are 7 numbers in the STRING.
  583.         DrawImage menu_scorefont,100+((i-1)*24),SCREEN_HEIGHT-44,Int(Mid(HI_SCORE_STR,i,1))
  584.                 ;let's break this up.. firstly "100+((i-1)*24"
  585.                 ;the leftmost number in the string first (i = 1)
  586.                 ;x position = 100+((i-1)*24
  587.                 ;=100+((0)*24)
  588.                 ;=100+(0)
  589.                 ;=100
  590.                 ;the next number in the string (i = 2)
  591.                 ;x position = 100+((i-1)*24
  592.                 ;=100+((1)*24)
  593.                 ;=100+(24)
  594.                 ;=124
  595.                 ;the next number in the string (i = 3)
  596.                 ;x position = 100+((i-1)*24
  597.                 ;=100+((2)*24)
  598.                 ;=100+(48)
  599.                 ;=148
  600.                 ;etc... this offsets each number in the seven digit long number across the screen!
  601.                 
  602.                 ;Okay.. Now the "Int(Mid(HI_SCORE_STR,i,1))" bit..
  603.                 ;"Mid(HI_SCORE_STR,i,1)" takes one character, starting at "i" from the string "HI_SCORE_STR".
  604.                 ;For example, if i=4 and HI_SCORE_STR = "0023560" then
  605.                 ;"Mid(HI_SCORE_STR,i,1)" would give us "3".
  606.                 ;the "INT" bit turns the ASCII string value "3" into an integer number 3.
  607.  
  608.                 ;Finally, the "Int(Mid(HI_SCORE_STR,i,1))" bit is the frame number in an Animation Image (remember LoadAnimImage before?)
  609.                 ;Although the "menu_score_font" picture isn't technically an animation, this is a clever alternate use for AnimImages, where you can
  610.                 ;simply calculate which image to show, by it's "frame" position within the animation.
  611.                 ;if you check the file "menu-scorefont.bmp" in Paint Shop Pro, you'll see that the 3rd image from the left is, in fact, a pictorial number 3.
  612.         DrawImage menu_scorefont,(SCREEN_WIDTH)-167+((i-1)*24),SCREEN_HEIGHT-44,Int(Mid(LAST_SCORE_STR,i,1))
  613.                 ;exactly the same thing, but using LAST_SCORE_STR instead of HI_SCORE_STR!
  614.     Next
  615.     DrawImage menu_thanks,(SCREEN_WIDTH/2)-(ImageWidth(menu_thanks)/2),SCREEN_HEIGHT-15
  616.  
  617.     ;depending on the value set earlier in "menu_loop_update()" this draws one of the two ships at the relevant coordinates on-screen
  618.     ;menu_ship_hor is the x position, and is set once per "scroll up the screen" in menu_loop_update().
  619.     ;menu_ship_ver is the y position, which is repeatedly changed in menu_loop_update() to scroll the ships up the screen!
  620.     Select menu_ship_type
  621.         Case 1
  622.             DrawImage menu_ship1,menu_ship_hor,menu_ship_ver
  623.         Case 2
  624.             DrawImage menu_ship2,menu_ship_hor,menu_ship_ver
  625.     End Select
  626.     
  627.     ;Remember before, I was saying that "menu_frame" would be used to flash the "START GAME" caption on and off?
  628.     ;when "menu_frame" got to 25, the variable "menu_start_stat" was flipped between 1 or 0
  629.     If menu_start_stat = 1 Then
  630.         ;if the variable "menu_start_stat" = 1 then draw the caption. If it isn't, ignore drawing the caption.
  631.         ;On and off, on and off. Simple as that! This technique will be used again later for the PAUSE and GAME_OVER captions!
  632.         DrawImage menu_start,(SCREEN_WIDTH/2)-(ImageWidth(menu_start)/2),(SCREEN_HEIGHT/2)+(ImageHeight(menu_start)*4)
  633.     End If
  634.  
  635.     ;Remember when we checked to see if the user had pressed the "SAVESCREEN" button, earlier?
  636.     ;if they did, we set FLAG_SAVESCREEN to 1. Now this is where that takes effect..
  637.     If FLAG_SAVESCREEN=1 Then
  638.         SaveBuffer (BackBuffer(),"CRMenuScreen.bmp")
  639.             ;the SaveBuffer command outputs the contents of the named buffer (in this case "BackBuffer()") to the named file, in a BMP format.
  640.         FLAG_SAVESCREEN = 0
  641.             ;after we've saved the screen, we reset the FLAG to 0, so that when we come back for the next "menu_draw_update", it won't save
  642.             ;another picture. (i.e.: it only saves 1 picture for each keypress of the "SAVESCREEN" button!)
  643.             ;This is useful for getting working screenshots of your project to impress your mates!! :)
  644.     End If 
  645.     Flip    ;finally, FLIP everything on the backbuffer() and show it on the frontbuffer(), i.e.: your monitor!!
  646. End Function
  647.  
  648. ;this function keeps the game loop going.. It starts playing tunes and sets a couple of variables. 
  649. ;Then it goes into a never ending loop which carries out a sequence of checks and function calls, until such time as we want to stop it!
  650. Function game_loop()
  651.     FLAG_GAMEON = 1 ;tells the program that the game is running.
  652.     game_initialise()     ;calls a function called "game_initialise()" (which is next in the code) which
  653.                         ;just gives the player full energy and a score of 0 etc..)
  654.     music_game_level = 0.3    ;the XM tune I've used is an old Amiga Module from a game called Dynablaster
  655.                             ;it's a bit loud to go with the game, though, so I want it's volume to be lower than
  656.                             ;normal.. see in a second..
  657.     sound_hyperjump_channel = PlaySound(sound_hyperjump)     ;The game starts in what seems to be mid-hyperjump, but because
  658.                                                             ;this sound is normally called after a keypress, I've got to do it manually
  659.                                                             ;just this once! ;)
  660.     Repeat        ;as with the menu, we want to cycle though the process of updating/drawing forever, until such time as the game has ended.
  661.         If FLAG_GAMEON = 1 Then        ;.. so, if FLAG_GAMEON is 1, then "do" the following.
  662.             game_loop_update()                                ;call the game_loop_update() function
  663.             If ChannelPlaying(music_menu) = True Then        ;this bit slowly turns down the menu music, until the music_menu_level is 0..
  664.                 music_menu_level = music_menu_level -.01    
  665.                 ChannelVolume music_menu, music_menu_level
  666.                 If music_menu_level <= 0 Then                ;.. then turns it off completely!
  667.                     StopChannel(music_menu)
  668.                 End If
  669.             End If
  670.         Else
  671.             FlushKeys                ;if FLAG_GAMEON isn't 1, then instead of ENDing the program (as we did from the menu), this time
  672.             Exit                    ;we EXIT the function, which effectively takes us back to the line after "game_loop()" was originally
  673.                                     ;called, back in "menu_loop_update()"
  674.         End If
  675.         If ChannelPlaying(music_game) = False Then        ;once again, this checks if the game music has finished playing
  676.             music_game = PlayMusic("Dynablaster.xm")    ;and starts it again..
  677.             ChannelVolume music_game, music_game_level    ;remembering that we want to play it quieter, so set it's CHANNELVOLUME to music_game_level (as set a second ago!)
  678.         End If
  679.     Forever
  680. End Function
  681.  
  682. ;As described a minute ago, this function sets up the game variables as they should be
  683. ;at the start of every game, i.e.: Player Shields are full, the score is 0 etc..
  684. Function game_initialise()
  685.     PLAYER_SCORE = 0
  686.     PLAYER_TIME = 0
  687.     PLAYER_ANGLE = 0
  688.     PLAYER_SPEED = 0
  689.     PLAYER_SHIELD = 192            ;the width of the game_level image is 192. Rather than working out a percentage of 100, it's much
  690.     PLAYER_BOOSTERS = 192        ;easier to use the width of the image on such BAR type displays.
  691.     PLAYER_CLOAK = 192            
  692.     PLAYER_JUMPS = 5
  693.     gameovercounter = 0
  694.     player_explosion_frame = 0
  695.     game_player_randomize()            ;calls a function that randomizes a player's position on the map
  696.     game_stars_randomize()            ;calls a function that randomizes the star positions
  697.  
  698.     ;this next bit is the first time you'll have seen a TYPE cycle.
  699.     ;Just like a normal "For i = 0 to 20" loop, this goes through each Version of a type
  700.     ;and set's it's properties. (i.e.: That FISH type has a SCALES property. Here we tell it that this particular Fish's Scales are GOLD!)
  701.     For enemy.enemies=Each enemies
  702.         enemy\x=Rnd(0,GAME_AREA_X)        ;randomizes each "enemies"'s position on the map!
  703.         enemy\y=Rnd(0,GAME_AREA_Y)
  704.         enemy\energy = 100                    ;gives each "enemies" a full shield strength of 100
  705.         enemy\angle = Int(Rnd(0,72)) * 5    ;gives each "enemies" a random angle between 0 and 360, at increments of 5 degrees
  706.         enemy\maxspeed = Rnd(20,40)            ;gives each "enemies" a random maximum speed between 20 and 40 (a bit slower, and a bit faster than the player's
  707.                                             ;maximum speed (as originally coded by me. If you change the player's maximum speed, it will have no effect on 'them'!)
  708.         enemy\speed = 0
  709.         enemy\style = 1                        ;sets the "enemies"'s style to 1. Remember before when I said it would be easily possible to implement new styles of enemy?
  710.                                             ;well, this would be your starting point! :)
  711.                                             
  712.         enemy\exp_frame = 0                    ;like the player, an "enemies" has an explosion frame which is always zero(0) until it is ready to explode!
  713.                                             ;see later for the code which fire's an "enemies"'s final demise.
  714.  
  715.         enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)    ;The "enemies"'s distance to go defines how far it will fly on it's current course, before it
  716.                                                                 ;retargets and turns towards you. This is a fairly simple, but reasonably effective enemy A.I.
  717.         enemy\dist_travelled = 0            ;directly related to the "enemies"'s distance to go, is how far it has travelled up to now.
  718.  
  719.         enemy\gen = 1            ;a last minute addition, when an enemy dies and regenerates, it is worth more points to kill next time around, thanks to its GEN number.
  720.     Next
  721.     
  722.     For icon.icons = Each icons
  723.         icon\x = Rnd(0,GAME_AREA_X)        ;for each of the 4 icons on the play area at any one point, we need a random x and y position.
  724.         icon\y = Rnd(0,GAME_AREA_Y)
  725.     Next
  726. End Function
  727.  
  728. ;once again, like it's menu equivalent, "game_loop_update()" is a function which analyses player input, working out all the new
  729. ;coordinate positions and anything else which needs deciding before updating the screen display.
  730. Function game_loop_update()
  731.     frames = WaitTimer(timer)
  732.     For i = 1 To frames
  733.         If KeyDown(KEY_PAUSE)                                    ;checks to see if the user has pressed the "PAUSE" key
  734.             FlushKeys
  735.             If game_accept_pause = 1 And gameovercounter = 0    ;the "game_accept_pause" variable is used in the same way as "menu_accept_quit" earlier.
  736.                                                                 ;because we're using SCANCODES, the program will register a number of qualifying cases where
  737.                                                                 ;when this check is performed, the key is still held down (at 50 frames per second, if the user
  738.                                                                 ;held down the key for half a second, the KEYDOWN function would fire around 25 times!)
  739.                                                                 ;A check is made on the value of "game_over_counter" to see if the player has died - in which
  740.                                                                 ;case Pausing the game is not allowed.
  741.                                                                 
  742.                 If FLAG_PAUSE = 0 Then                            ;If FLAG_PAUSE is 0 then..
  743.                     FLAG_PAUSE = 1                                ;make FLAG_PAUSE = 1
  744.                     game_accept_pause = 0                        ;don't accept any more "PAUSE" button presses until "game_accept_pause" is set back to 1
  745.                     game_pause_frame = 1                        ;make "game_pause_frame" = 1 which, similarly to "menu_frame" earlier will enable the flashing of "PAUSED".
  746.                 Else
  747.                     FLAG_PAUSE = 0                                ;If FLAG_PAUSE isn't 0 (the game was paused) then..
  748.                     game_accept_pause = 0                        ;do exactly the same, but set FLAG_PAUSE to 0.
  749.                     game_pause_frame = 1
  750.                 End If
  751.             End If
  752.         End If
  753.         If KeyDown(KEY_SAVESCREEN)        ;If the "SCREENSAVE" button is pressed..
  754.             FlushKeys                    ;this functions exactly the same as in menu_loop_update()
  755.             FLAG_SAVESCREEN = 1
  756.         End If
  757.         If KeyDown(KEY_QUIT)        ;If the "QUIT" button is pressed..
  758.             FlushKeys
  759.             hypercount = 0
  760.             cloakon = 0
  761.             FLAG_GAMEON=0             ;set FLAG_GAMEON to equal 0. Back in the "game_loop()" function, this will cause the code to jump back to the menu.
  762.         End If
  763.  
  764.         If FLAG_PAUSE = 0 Then                            ;this is really easy! If the game is paused then *don't* do any of the following code. No values will change,
  765.                                                         ;hence nothing will move on the screen when it comes to updating it later! :)
  766.                                                         
  767.             If gameovercounter = 0 Then                    ;if the game is still in progress, i.e.: "gameovercounter" = 0 (the player is still alive) then
  768.                                                         ;check for the following keypresses from the user - otherwise there's no point!
  769.                                                         
  770.                 If KeyDown(KEY_HYPER)                    ;if the "HYPER" key is pressed then..
  771.                     If PLAYER_JUMPS > 0 Then
  772.                         If hypercount = 0 Then                ;(if "hypercount" is 0, then we're not already in the middle of a HyperJump, so let's set things off!)
  773.                             hypercount = 1                        ;by setting "hypercount" to 1, we'll set off a chain of events later on..
  774.                             sound_hyperjump_channel = PlaySound(sound_hyperjump)        ;play the Hyperjump soundeffect on the appropriate channel reference
  775.                             PLAYER_JUMPS = PLAYER_JUMPS - 1        ;subtract the number of Jumps a player has left by 1
  776.                             If PLAYER_JUMPS <= 0 Then            ;if the number of jumps left is 0 or less, then the above subtraction will make it "-1", so..
  777.                                 PLAYER_JUMPS = 0                ;put it back to 0.
  778.                             End If
  779.                         End If
  780.                     End If
  781.                     FlushKeys
  782.                 End If
  783.                 If hypercount = 0 Then                        ;as long as we're not in the middle of a hyperjump, do the following..
  784.                 
  785.                     If KeyDown(KEY_CLOAK)            ;if the CLOAK key is pressed then
  786.                     
  787.                         If PLAYER_CLOAK > 2 Then        ;if the player has enough (2 points of) PLAYER_CLOAK left, then..
  788.                             cloakon = cloakon + 1                                    ;the cloakon value is incremented so that later on, we can do the flickering effect
  789.                             PLAYER_CLOAK = PLAYER_CLOAK - INCR_CLOAK_DOWN            ;subtract some PLAYER_CLOAK ability at a rate of "INCR_CLOAK_DOWN"
  790.                             
  791.                             If ChannelPlaying(sound_cloak_channel) = False Then        ;because the sound effect is triggered by a KeyDown event, it will fire repeatedly,
  792.                                 sound_cloak_channel = PlaySound(sound_cloak)        ;which makes an almighty noise as the echo of the sound effect builds on top of 
  793.                             End If                                                    ;eachother! By using this "If it's playing then do nothing, otherwise Play it again"
  794.                                                                                     ;peice of code, the sample plays once, then if the key is still held down, then it'll
  795.                                                                                     ;play it another once.. and so on.. (Take out the IF and the END IF to see what I mean!)
  796.                         Else                            ;if the player doesn't have enough PLAYER_CLOAK left then
  797.                             cloakon = 0                        ;reset the "cloakon" value to 0
  798.                             PLAYER_CLOAK = 0                ;Keep the PLAYER_CLOAK value at 0, so that it doesn't build up...
  799.                         End If
  800.                         FlushKeys
  801.                     Else                            ;if the CLOAK key isn't pressed then
  802.                         cloakon = 0                            ;reset the "cloakon" value to 0
  803.                         If PLAYER_CLOAK < 192                                ;if the player has less than the top value (192 points) of PLAYER_CLOAK then..
  804.                             PLAYER_CLOAK = PLAYER_CLOAK + INCR_CLOAK_UP            ;Slowly build up the PLAYER_CLOAK value.
  805.                         Else
  806.                             PLAYER_CLOAK = 192                                ;otherwise cap the PLAYER_CLOAK value at 192 points.
  807.                         End If
  808.                         FlushKeys
  809.                     End If
  810.                     If KeyDown(KEY_BOOST)                            ;the BOOST key works in exactly the same way as the CLOAK key
  811.                         If PLAYER_BOOSTERS > 2 Then
  812.                             If PLAYER_SPEED < (SPEED_MAX*3) Then
  813.                                 PLAYER_SPEED = PLAYER_SPEED + (INCR_SPEED * 3)
  814.                             End If
  815.                             If ChannelPlaying(sound_boosters_channel) = False Then
  816.                                 sound_boosters_channel = PlaySound(sound_boosters)
  817.                             End If
  818.                             PLAYER_BOOSTERS = PLAYER_BOOSTERS - INCR_BOOSTERS_DOWN
  819.                         Else
  820.                             PLAYER_BOOSTERS = 0
  821.                         End If
  822.                         FlushKeys
  823.                     Else
  824.                         If PLAYER_BOOSTERS < 192
  825.                             PLAYER_BOOSTERS = PLAYER_BOOSTERS + INCR_BOOSTERS_UP
  826.                         Else
  827.                             PLAYER_BOOSTERS = 192
  828.                         End If
  829.                         FlushKeys
  830.                     End If
  831.                     If KeyDown(KEY_FIRE) Then                    ;if the "FIRE" key is pressed, then..
  832.                         If bulletlimiter = 0 Then                    ;the "bulletlimiter" value works in exactly the same way as "game_accept_pause" earlier
  833.                                                                     ;in that we don't want too many bullets spraying out of the player, due to SCANCODE/framerate issues
  834.                             bulletlimiter = 1                        ;so we set the "bulletlimiter value to 1, so that until we say so (a bit later) no more "FIRE" keypresses
  835.                                                                     ;will trigger.
  836.                                                                     
  837.                             createbullet(PLAYER_X,PLAYER_Y,PLAYER_ANGLE,PLAYER_SPEED,1)        ;however, assuming we've got a successful "FIRE" event, let's create some bullets
  838.                                                                                             ;on the screen by calling the "createbullet()" function.. This is pretty cool, so
  839.                                                                                             ;see the function itself later on for explainations!
  840.                                                                                             
  841.                             sound_player_laser_channel = PlaySound(sound_player_laser)    ;play the appropriate sound effect on it's channel
  842.                         End If
  843.                         FlushKeys
  844.                     End If
  845.                     If KeyDown(KEY_CLOCKWISE)                            ;if "CLOCKWISE" key is pressed then..
  846.                         PLAYER_ANGLE = PLAYER_ANGLE + INCR_ROTATE            ;Add "INCR_ROTATE" degrees to the current PLAYER_ANGLE
  847.                         FlushKeys
  848.                         If PLAYER_ANGLE >= 360 Then                            ;if the PLAYER_ANGLE is 360, then reset it to 0.
  849.                             PLAYER_ANGLE = PLAYER_ANGLE - 360
  850.                         End If
  851.                     End If
  852.                     If KeyDown(KEY_ANTICWISE)                            ;exactly the same, but Subtract "INCR_ROTATE" from the player angle and
  853.                         PLAYER_ANGLE = PLAYER_ANGLE - INCR_ROTATE        ;reset it to (for example) 355, if the angle is -5.
  854.                         FlushKeys
  855.                         If PLAYER_ANGLE < 0 Then
  856.                             PLAYER_ANGLE = PLAYER_ANGLE + 360
  857.                         End If
  858.                     End If
  859.                     If KeyDown(KEY_SPEEDUP) Then                        ;if the "SPEEDUP" key is pressed.
  860.                         If PLAYER_SPEED < SPEED_MAX                            ;as long as the player speed is less than the maximum speed (SPEED_MAX), then
  861.                             PLAYER_SPEED = PLAYER_SPEED + INCR_SPEED        ;Add "INCR_SPEED" to the player's speed value
  862.                             FlushKeys
  863.                         Else
  864.                             PLAYER_SPEED = PLAYER_SPEED - INCR_SLOW            ;if the PLAYER_SPEED is not less than the maximum speed then take "INCR_SLOW" off of it!
  865.                             FlushKeys
  866.                         End If
  867.                     Else                                                ;if the key isn't being pressed, then..
  868.                         If PLAYER_SPEED > 0 Then                            ;as long as the player speed is greater than 0, then take "INCR_SLOW" off the current value
  869.                             PLAYER_SPEED = PLAYER_SPEED - INCR_SLOW            ;(this is an easy "No power" decelaration for the space ship)
  870.                         End If
  871.                         FlushKeys
  872.                     End If
  873.                     If KeyDown(KEY_SPEEDDOWN)                            ;exactly the same thing, but with the ship's thrusters in reverse! :)
  874.                         If PLAYER_SPEED > SPEED_MIN
  875.                             PLAYER_SPEED = PLAYER_SPEED - INCR_SPEED
  876.                             FlushKeys
  877.                         Else
  878.                             PLAYER_SPEED = SPEED_MIN
  879.                             FlushKeys
  880.                         End If
  881.                     Else
  882.                         If PLAYER_SPEED < 0 Then
  883.                             PLAYER_SPEED = PLAYER_SPEED + INCR_SLOW
  884.                         End If
  885.                     End If
  886.                 End If    ;end of the "If we're not in the middle of a hyperjump" IF statement
  887.                 
  888.                 ;this next peice of code updates the player position on the map, relative to it's Speed and Angle and it's last position
  889.                 PLAYER_X = PLAYER_X + (PLAYER_SPEED*(Sin(PLAYER_ANGLE)/2))
  890.                 PLAYER_Y = PLAYER_Y - (PLAYER_SPEED*(Cos(PLAYER_ANGLE)/2))
  891.                 If PLAYER_X < 0 Then                        ;if the PLAYER_X value is less than 0, then wrap your position around the map
  892.                     PLAYER_X = (PLAYER_X + GAME_AREA_X)        ;by adding the GAME_AREA_X value to the negative value, i.e.: -5 becomes 19995 on a 20000 X pixel map.
  893.                 End If
  894.                 If PLAYER_X > GAME_AREA_X Then                ;the same in reverse, i.e. 20004 becomes 4 on the same map.
  895.                     PLAYER_X = (PLAYER_X - GAME_AREA_X)
  896.                 End If
  897.                 If PLAYER_Y < 0 Then                        ;and now the same for the Y direction
  898.                     PLAYER_Y = (PLAYER_Y + GAME_AREA_Y)
  899.                 End If
  900.                 If PLAYER_Y > GAME_AREA_Y Then
  901.                     PLAYER_Y = (PLAYER_Y - GAME_AREA_Y)
  902.                 End If
  903.             End If        ;end of the "If the game is still running ('gameovercounter')" IF Statement
  904.     
  905.             For icon.icons=Each icons                ;the "icons" don't move from their randomly set x,y position, so all we need to do for them is
  906.                 icon\frame = icon\frame+.5            ;update their animation frame number. There are 6 frames, and we're incrementing at 0.5 frames per update.
  907.                 If Int(icon\frame) = 6 Then            ;in real terms, this means we'll be updating the frame number every 2 updates.
  908.                     icon\frame = 0                    ;Because the icon animations are simple 0 to 5 cycling animations, when the frame number reaches 6, we flip it back to 0
  909.                 End If                                ;to start the sequence again.
  910.             Next
  911.             
  912.             ;the following code section is probably the most complex in the game, because it's the Enemy Artificial Intelligence
  913.             ;Reader's of a nervous disposition might want to skip this - I know I did! :)))
  914.             For enemy.enemies=Each enemies        ;for each version of the "enemies" type..
  915.  
  916.                 If enemy\exp_frame > 0 Then                        ;remember before, I said we were going to blow up the player and enemies, just by setting a value?
  917.                     enemy\exp_frame = enemy\exp_frame + .5        ;well, this is it! if this "enemies" exp_frame is greater than 0, then start increasing the Explosion
  918.                 End If                                            ;animation frame number (notice the same "update every two screen refreshes" technique?)
  919.  
  920.                 If cloakon = 0        ;if the player's CLOAKing device is off, then do the following bit. Otherwise, ignore it..
  921.                     ;indeed. This next bit makes the enemies home in on you and shoot you to peices. If your cloak is on, they can't see you, so don't do the intelligence tests
  922.  
  923.                     If enemy\exp_frame = 0 Then            ;as long as this version of "enemies" isn't busy exploding..
  924.  
  925.                         ;this bit checks the distances to the left, right, top and bottom of the enemy, relative to the player, to decide which way to fly would be the best
  926.                         ;intercept route. I tell you, these are vicious dedicated little oiks! :)
  927.                         temp_x1# = PLAYER_X - enemy\x         ;x distance to player on the right
  928.                         temp_y1# = PLAYER_Y - enemy\y        ;y distance to player on the top
  929.                         temp_x2# = enemy\x - PLAYER_X         ;x distance to player on the left
  930.                         temp_y2# = enemy\y - PLAYER_Y        ;y distance to player on the bottom
  931.                         If temp_x1# < 0 Then                    ;if the values are bigger than the game area, or less than 0, then wrap them
  932.                             temp_x1# = temp_x1# + GAME_AREA_X    ;around the game map, like with the player before.
  933.                         End If
  934.                         If temp_x1# > GAME_AREA_X Then
  935.                             temp_x1# = temp_x1# - GAME_AREA_X
  936.                         End If
  937.                         If temp_y1# < 0 Then
  938.                             temp_y1# = temp_y1# + GAME_AREA_Y
  939.                         End If
  940.                         If temp_x1# > GAME_AREA_X Then
  941.                             temp_y1# = temp_y1# - GAME_AREA_Y
  942.                         End If
  943.                         If temp_x2# < 0 Then
  944.                             temp_x2# = temp_x2# + GAME_AREA_X
  945.                         End If
  946.                         If temp_x2# > GAME_AREA_X Then
  947.                             temp_x2# = temp_x2# - GAME_AREA_X
  948.                         End If
  949.                         If temp_y2# < 0 Then
  950.                             temp_y2# = temp_y2# + GAME_AREA_Y
  951.                         End If
  952.                         If temp_x2# > GAME_AREA_X Then
  953.                             temp_y2# = temp_y2# - GAME_AREA_Y
  954.                         End If
  955.  
  956.                         ;this bit compares the two x directions to see which one is smaller            
  957.                         If Abs(temp_x1#) < Abs(temp_x2#) Then    ;the ABS function always gives you the "+VE" version of a number, so -1 comes out as 1 and 2 comes out as 2
  958.                             temp_x# = Abs(temp_x1#)        ;if "Temp_x1" is the smallest, make this the "best" x distance 
  959.                             xdir = -1
  960.                         Else
  961.                             temp_x# = Abs(temp_x2#)        ;otherwise if "Temp_x2" is the smallest, make this the "best" x distance
  962.                             xdir = 1
  963.                         End If
  964.                         If Abs(temp_y1#) < Abs(temp_y2#) Then    ;same with the y directions
  965.                             temp_y# = Abs(temp_y1#)
  966.                             ydir = -1
  967.                         Else
  968.                             temp_y# = Abs(temp_y2#)
  969.                             ydir = 1
  970.                         End If
  971.                         
  972.                         ;because we used the ABS function, we've lost the original direction of the value's units, so using the xdir and ydir
  973.                         ;values we just set over there, we can rebuild that directional picture
  974.                         If xdir = 1 And ydir = 1 Then
  975.                             sector = 4                        ;top left
  976.                         ElseIf xdir = 1 And ydir = -1 Then
  977.                             sector = 3                        ;bottom left
  978.                         ElseIf xdir = -1 And ydir = -1 Then
  979.                             sector = 2                        ;bottom right
  980.                         ElseIf xdir = -1 And ydir = 1 Then
  981.                             sector = 1                        ;top right
  982.                         End If
  983.                         
  984.                         ;finally, we're going to use our knowledge of the shortest distance between this "enemies" and the player
  985.                         ;using PYTHAGORAS theorum to get the angle between them.
  986.  
  987.                         temp_x# = Abs(temp_x# / 200)        ;this bit just makes the number's smaller and more manageable
  988.                         temp_y# = Abs(temp_y# / 200)
  989.                         temp_hyp# = (temp_x#*temp_x#) + (temp_y#*temp_y#)    ;PYTHAGORAS would be proud
  990.                         temp_hyp# = Sqr(temp_hyp#)                            ;.. oh and Mrs Pennington, my Maths teacher! :)
  991.                         enemy\dest_adj = temp_x#        ;these Type properties aren't used anymore, except in the DEBUG version
  992.                         enemy\dest_opp = temp_y#
  993.                         enemy\dest_hyp = temp_hyp#
  994.                         enemy\dest_angle = ASin(temp_y#/temp_hyp#)    ;finally, back to Trigonometry, the angle is revealed.
  995.                         
  996.                         ;now, once again, because we lost the directions of the original value's units, the angle we've just got will only be between 0 and 90 degrees
  997.                         ;consequently, we've got to decide how to get 91 to 359 degrees back, which we can do with our "sector" values
  998.                         Select sector
  999.                             Case 1
  1000.                                 enemy\dest_angle = 90-enemy\dest_angle    ;between 0 and 90
  1001.                             Case 2
  1002.                                 enemy\dest_angle = 90+enemy\dest_angle    ;between 90 and 180
  1003.                             Case 3
  1004.                                 enemy\dest_angle = 270-enemy\dest_angle    ;between 180 and 270
  1005.                             Case 4
  1006.                                 enemy\dest_angle = 270+enemy\dest_angle    ;between 270 and 360
  1007.                         End Select
  1008.                         
  1009.                         ;so, now our enemies know where to point themselves, let's not allow them to just mindlessly run into you!
  1010.                         If temp_hyp# < Rnd(1,1.5) And gameovercounter = 0 Then    ;if the distance between you and them is less than (a small, but random distance)
  1011.                                                                                 ;and the player is alive..
  1012.                             If enemy\bulletlimiter = 0 Then                                ;exactly like the player shooting, the enemie's bullet needs limiting
  1013.                                 enemy\bulletlimiter = 1
  1014.                                 createbullet(enemy\x,enemy\y,enemy\angle,enemy\speed,2)
  1015.                                 sound_enemy_laser_channel = PlaySound(sound_enemy_laser)
  1016.                             End If
  1017.                             whichway = Rand(1,100)                            ;the enemy comes at you, shoots, then flys off in the opposite direction, however,
  1018.                             If whichway > 50 Then                            ;to give it a slightly random element, they can fly off to the left or the right
  1019.                                 enemy\dest_angle = enemy\dest_angle + 180    ;of themselves. This gives them a slightly less "patterny" feel.
  1020.                             Else
  1021.                                 enemy\dest_angle = enemy\dest_angle - 180
  1022.                             End If
  1023.                             enemy\dist_travelled = enemy\dist_to_go            ;cancel their "distance still to travel before changing course" action by
  1024.                                                                             ;prematurely setting the distance travelled to the distance to go value.
  1025.                                                                             
  1026.                             slowdown = 0            ;if the "enemies" is near enough, we don't want him to stop as he turns away from you.
  1027.                         Else
  1028.                             slowdown = 1            ;at greater distances, we do want the "enemies" to stop, turn and then fly at you.. See later..
  1029.                         End If
  1030.     
  1031.                         ;this is the enemy bullet limiter. Essentially, if an enemy fire's a bullet then it can't fire another one until this
  1032.                         ;counter reaches 10. (in another 10 frames, which at 50 fps would be in a fifth of a second.
  1033.                         If enemy\bulletlimiter > 0 Then
  1034.                             enemy\bulletlimiter = enemy\bulletlimiter + 1
  1035.                             If enemy\bulletlimiter = 10 Then ;value essentially sets the enemies fire-rate (the lower the number, the faster the fire rate!)
  1036.                                 enemy\bulletlimiter = 0    ;allows the enemy to fire another bullet.
  1037.                             End If
  1038.                         End If
  1039.                         
  1040.                         ;this bit works out what the destination angle given before looks like in increments of 5 degrees.
  1041.                         ;the angle the enemy *wants* to face is, for example, 212 degrees. The closest angle I drew in Paint Shop Pro is 210 degrees
  1042.                         If enemy\dest_angle >= 360 Then
  1043.                             enemy\dest_angle = enemy\dest_angle - 360
  1044.                         ElseIf enemy\dest_angle < 0 Then
  1045.                             enemy\dest_angle = enemy\dest_angle + 360
  1046.                         End If
  1047.                         ;this next line says does the 212 to 210 conversion, i.e.: 
  1048.                         ;212 / 5 = 42.4
  1049.                         ;42.4 converted to an INTeger is 42
  1050.                         ;5 * 42 = 210
  1051.                         enemy\dest_angle = 5 * Int(enemy\dest_angle / 5)
  1052.             
  1053.                         ;this next section works out the quickest rotation that the "enemies" ship can do to face the direction it wants to be
  1054.                         ;i.e.: if it's currently at 20 degrees, and wants to be facing 45 degrees, then he's got 25 degrees to go to the right, or 335 degrees to the left.
  1055.                         ;guess which one would be more sensible in a life-or-death situation?
  1056.                         If enemy\angle > enemy\dest_angle Then
  1057.                             enemy\rotate_angle = enemy\angle - enemy\dest_angle
  1058.                         ElseIf enemy\angle < enemy\dest_angle
  1059.                             enemy\rotate_angle = 0 - (enemy\dest_angle - enemy\angle)
  1060.                         Else
  1061.                             enemy\rotate_angle = 0
  1062.                         End If
  1063.                         
  1064.                         If enemy\rotate_angle > 180 Then
  1065.                             enemy\rotate_angle = 0-(360-enemy\rotate_angle)
  1066.                         End If
  1067.                         If enemy\rotate_angle < -180 Then
  1068.                             enemy\rotate_angle = (360+enemy\rotate_angle)
  1069.                         End If
  1070.  
  1071.                         ;this bit is working out how far the "enemies" has travelled since the last update and adds it to the "dist_travelled" property
  1072.                         dist_x# = dist_x# + (enemy\speed*(Sin(enemy\angle)/2))
  1073.                         dist_y# = dist_y# - (enemy\speed*(Cos(enemy\angle)/2))
  1074.                         enemy\dist_travelled = enemy\dist_travelled + Sqr((dist_x#*dist_x#) + (dist_y#*dist_y#))
  1075.             
  1076.                         ;Before, we said that the enemy should travel a certain distance before he retargets and homes in on you.
  1077.                         ;this next section deals with the event once the "enemies" has travelled that distance!
  1078.                         If enemy\dist_travelled > enemy\dist_to_go Then
  1079.                             If slowdown = 1 Then                ;depending on the value of "slowdown", the "enemies" will (or will not) slow down as he turns to face you.
  1080.                                 If enemy\speed > 0 Then
  1081.                                     enemy\speed = enemy\speed - (5*INCR_SLOW)
  1082.                                 Else
  1083.                                     enemy\speed = 0
  1084.                                 End If
  1085.                             End If
  1086.                             ;based on the decision made a second ago, about which was the quickest way to rotate to face you fastest..
  1087.                             If enemy\rotate_angle < 0 Then
  1088.                                 If Not enemy\angle = enemy\dest_angle Then
  1089.                                     enemy\angle = enemy\angle + 5                ;rotate the "enemies" right until its angle is correct
  1090.                                     If enemy\angle >=360 Then
  1091.                                         enemy\angle = 360-enemy\angle            ;flip the angle back to 0 when it gets to 360
  1092.                                     End If
  1093.                                 Else
  1094.                                     enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)    ;once the angle is correct, randomly create another distance to
  1095.                                     enemy\dist_travelled = 0                                ;travel until the next check, and reset the "travelled" distance to 0
  1096.                                 End If
  1097.                             Else
  1098.                                 If Not enemy\angle = enemy\dest_angle Then
  1099.                                     enemy\angle = enemy\angle - 5                ;exactly the same, but rotating left
  1100.                                     If enemy\angle < 0 Then
  1101.                                         enemy\angle = enemy\angle+360
  1102.                                     End If
  1103.                                 Else
  1104.                                     enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)
  1105.                                     enemy\dist_travelled = 0
  1106.                                 End If
  1107.                             End If
  1108.                             
  1109.                         Else    ;if the "enemies" has not reached his destination "distance to go" value then
  1110.                         
  1111.                             If slowdown = 1 Then
  1112.                                 If enemy\speed < enemy\maxspeed Then                ;speed up the enemy until he reaches maximum speed
  1113.                                     enemy\speed = enemy\speed + (5*INCR_SPEED)
  1114.                                 Else
  1115.                                     enemy\speed = enemy\maxspeed
  1116.                                 End If
  1117.                             Else                                                    ;if he's within a certain distance, only allow him to
  1118.                                 If enemy\speed < enemy\maxspeed/2 Then                ;fly at half speed
  1119.                                     enemy\speed = enemy\speed + (5*INCR_SPEED)
  1120.                                 Else
  1121.                                     enemy\speed = enemy\maxspeed / 2
  1122.                                 End If
  1123.                             End If
  1124.                         End If
  1125.                         
  1126.                     End If    ;end of the "is enemy in the middle of exploding" IF statement
  1127.                     
  1128.                 End If    ;end of the "is the Player's CLOAKing device on?" IF statement
  1129.                 
  1130.                 enemy\x = enemy\x + (enemy\speed*(Sin(enemy\angle)/2))        ;update the "enemies" x and y positions, relative to its Speed and Angle
  1131.                 enemy\y = enemy\y - (enemy\speed*(Cos(enemy\angle)/2))        ;exactly the same code as the Player's positions, earlier
  1132.                 If enemy\x < 0 Then
  1133.                     enemy\x = (enemy\x + GAME_AREA_X)
  1134.                 End If
  1135.                 If enemy\x > GAME_AREA_X Then
  1136.                     enemy\x = (enemy\x - GAME_AREA_X)
  1137.                 End If
  1138.                 If enemy\y < 0 Then
  1139.                     enemy\y = (enemy\y + GAME_AREA_X)
  1140.                 End If
  1141.                 If enemy\y > GAME_AREA_Y Then
  1142.                     enemy\y = (enemy\y - GAME_AREA_Y)
  1143.                 End If
  1144.                 
  1145.             Next    ;end of the ENEMIES for loop
  1146.             
  1147.             
  1148.             ;this next bit of code creates the "simple but effective" Hyperjump event, based entirely on the value of "hypercount" being set to 1, earlier in the code.
  1149.             If hypercount > 0 Then
  1150.                 If (hypercount/2 = Int(hypercount/2)) Then    ;this line says "If the value of 'hypercount' is an EVEN number"
  1151.                                                             ;because 5 (an odd number) would be 2.5 when devided by 2, but conversion to an INTeger gives 3.
  1152.                                                             ;2.5 does NOT equal 3!
  1153.                     ;all of this simply rotates the HyperJump ships in different offset directions
  1154.                     ;the only difference is, we're not bothering with degrees here, just animation frame numbers, i.e.: 355 degrees is frame 71 (i.e.: 355/5 degree increment)
  1155.                     frame1 = frame1 + 3
  1156.                     frame2 = frame2 - 3
  1157.                     frame3 = frame1 + 9
  1158.                     frame4 = frame2 - 9
  1159.                     frame5 = frame1 + 36
  1160.                     frame6 = frame2 - 36
  1161.                     frame7 = frame1 + 54
  1162.                     frame8 = frame2 - 54
  1163.                     If frame1 >=72 Then
  1164.                         frame1 = frame1-72
  1165.                     End If
  1166.                     If frame1 < 0 Then
  1167.                         frame1 = frame1+72
  1168.                     End If
  1169.                     If frame2 >=72 Then
  1170.                         frame2 = frame2-72
  1171.                     End If
  1172.                     If frame2 < 0 Then
  1173.                         frame2 = frame2+72
  1174.                     End If
  1175.                     If frame3 >=72 Then
  1176.                         frame3 = frame3-72
  1177.                     End If
  1178.                     If frame3 < 0 Then
  1179.                         frame3 = frame3+72
  1180.                     End If
  1181.                     If frame4 >=72 Then
  1182.                         frame4 = frame4-72
  1183.                     End If
  1184.                     If frame4 < 0 Then
  1185.                         frame4 = frame4+72
  1186.                     End If
  1187.                     If frame5 >=72 Then
  1188.                         frame5 = frame5-72
  1189.                     End If
  1190.                     If frame5 < 0 Then
  1191.                         frame5 = frame5+72
  1192.                     End If
  1193.                     If frame6 >=72 Then
  1194.                         frame6 = frame6-72
  1195.                     End If
  1196.                     If frame6 < 0 Then
  1197.                         frame6 = frame6+72
  1198.                     End If
  1199.                     If frame7 >=72 Then
  1200.                         frame7 = frame7-72
  1201.                     End If
  1202.                     If frame7 < 0 Then
  1203.                         frame7 = frame7+72
  1204.                     End If
  1205.                     If frame8 >=72 Then
  1206.                         frame8 = frame8-72
  1207.                     End If
  1208.                     If frame8 < 0 Then
  1209.                         frame8 = frame8+72
  1210.                     End If
  1211.                 End If    ;end of the "if hypercount is EVEN" IF statement
  1212.                 
  1213.                 ;this bit increases the value of "hypercount" until it reaches 200
  1214.                 hypercount = hypercount + 1
  1215.                 If hypercount > 0 And hypercount <= 102 Then    ;between 0 and 102, the player speed increases
  1216.                     PLAYER_SPEED = PLAYER_SPEED + 2
  1217.                 ElseIf hypercount > 102 And hypercount < 200 Then    ;between 102 and 200, the player speed decreases (but only if FLAG_GAMESTARTER is 0)
  1218.                     If FLAG_GAMESTARTER = 0 Then                    ;this is because when the game starts, the player speed is 0, but we've faked being in
  1219.                         PLAYER_SPEED = PLAYER_SPEED - 2                ;the middle of a hyperjump. Without this FLAG, the player ship would start each game
  1220.                     End If                                            ;travelling at about -90 speed backwards, which would just be weird! :)
  1221.                 End If
  1222.                 If hypercount = 100 Then
  1223.                     game_stars_randomize()    ;half way through the Hyperjump sequence, the "game_starts_randomize()" function is called, which changes all the star positions    
  1224.                                             ;and depths, to give the impression we've moved to a completely different part of space
  1225.                 End If
  1226.                 If hypercount/10 = Int(hypercount/10) Then
  1227.                     game_player_randomize()        ;every 10 updates, the function "game_player_randomize()" is called. This randomly jumps the player around the map
  1228.                                                 ;and confuses the hell out of the bad guys! ;))
  1229.                 End If
  1230.                 If hypercount = 200 Then        ;if the "hypercount" variable reaches 200, then stop the sequence and reset the value back to 0
  1231.                     hypercount = 0
  1232.                     FLAG_GAMESTARTER = 0        ;also, when the game first starts we were in the middle of a hyperjump. Resetting this FLAG back to 0 means that
  1233.                                                 ;the next hyperjump sequence will decrease the speed after "hypercount" gets to 103
  1234.                 End If
  1235.             Else                            ;if we're not in the middle of a hyperjump event, then:
  1236.                 frame1=game_player_frame-1    ;this bit is just for the DEBUG mode. It was designed to check that 360 degrees became 0 degrees and vice versa correctly
  1237.                 frame2=game_player_frame+1
  1238.                 If frame1 < 0 Then
  1239.                     frame1 = frame1 + 72
  1240.                 End If
  1241.                 If frame2 >= 72 Then
  1242.                     frame2 = frame2 - 72
  1243.                 End If
  1244.             End If    ;end of the "Are we in the middle of a Hyperjump" IF statement
  1245.             
  1246.             ;the parralex stars move relative to the player and is just the same "menustars" number of stars
  1247.             ;scrolled at various speeds, wrapping around the screen.
  1248.             ;it's a fairly cheap, but effective way of creating a nice illusion of speed!
  1249.             If starson=1 Then                ;if, at the beginning of the program, you set "starson" to 0, the stars will disappear.
  1250.                                             ;the game would also feel pretty bloody wierd.. hold on.. yep.. Absolutely mad! Try it! :)
  1251.                 For star.stars=Each stars
  1252.                     ;the following two lines move each version of the "stars" Type an x and y distance relative to the player's speed and angle
  1253.                     ;with a devision relative to the depth of the star to make the smallest stars move slower than the biggest
  1254.                     ;thus we have our parallex effect.
  1255.                     
  1256.                     ;it might be of interest to know that these two lines were based on the OLDSKOOL demo which comes with Blitz Basic
  1257.                     ;and was the starting point for the whole CELESTIAL RIFT game concept! Thanks a lot, Mr Mikkel L°kke!! :)
  1258.                     star\y=(star\y+PLAYER_SPEED*(Cos(360-PLAYER_ANGLE)/(6-star\depth+1)))
  1259.                     star\x=(star\x+PLAYER_SPEED*(Sin(360-PLAYER_ANGLE)/(6-star\depth+1)))
  1260.                     ;the maximum pixel width of for the biggest star image is 5 pixels
  1261.                     ;the following IF statements wrap the stars around the screen border when they reach the extremities
  1262.                     If star\x < -5 Then
  1263.                         star\x = star\x + (SCREEN_WIDTH + 5)
  1264.                     End If
  1265.                     If star\x > SCREEN_WIDTH Then
  1266.                         star\x = star\x - (SCREEN_WIDTH + 5)
  1267.                     End If
  1268.                     If star\y <= -5 Then
  1269.                         star\y = star\y + (SCREEN_HEIGHT + 5)
  1270.                     End If
  1271.                     If star\y >= SCREEN_HEIGHT
  1272.                         star\y = star\y - (SCREEN_HEIGHT + 5)
  1273.                     End If
  1274.                 Next
  1275.             End If    ;end of the "are the stars going to be shown" IF statement
  1276.  
  1277.             ;the following lines calculate all the bullet positions, relative to their originally set SPEED and ANGLE from the "createbullet" function.
  1278.             For i = 0 To bulletnum-1
  1279.                 If bullets(i,4) > 0 Then        ;if the bullet isn't 0, i.e.: it's "on"
  1280.                 
  1281.                     bullets(i,0) = bullets(i,0) + (bullets(i,3)*(Sin(bullets(i,2))/2))    ;bullet x position = bullet x position + (bullet speed * (SIN (bullet angle) / 2)
  1282.                     bullets(i,1) = bullets(i,1) - (bullets(i,3)*(Cos(bullets(i,2))/2))    ;bullet y position = bullet y position + (bullet speed * (COS (bullet angle) / 2)
  1283.                                 ;try turning these last two lines off for a crazy pulsing effect of bullets that you can use
  1284.                                 ;to surround the player, creating a kind of enemy-deadly minefield.. Madness! :)
  1285.                     
  1286.                     bullets(i,5) = bullets(i,5) + 1        ;increases the animation frame of the bullet
  1287.                     If bullets(i,5) = 6 Then    ;if the animation frame is 6 then flip it back to 0 (the bullet animation runs frames 0, 1, 2, 3, 4, 5, 0, 1, 2 ... etc)
  1288.                         bullets(i,5) = 0
  1289.                     End If
  1290.                     
  1291.                     ;as with the player and enemies, this next bit wraps the bullets around the map extremities
  1292.                     If bullets(i,0) < 0 Then
  1293.                         bullets(i,0) = (bullets(i,0) + GAME_AREA_X)
  1294.                     End If
  1295.                     If bullets(i,0) > GAME_AREA_X Then
  1296.                         bullets(i,0) = (bullets(i,0) - GAME_AREA_X)
  1297.                     End If
  1298.                     If bullets(i,1) < 0 Then
  1299.                         bullets(i,1) = (bullets(i,1) + GAME_AREA_X)
  1300.                     End If
  1301.                     If bullets(i,1) > GAME_AREA_Y Then
  1302.                         bullets(i,1) = (bullets(i,1) - GAME_AREA_Y)
  1303.                     End If
  1304.                     
  1305.                     ;like the enemies "distance from player", this bit checks if a bullet has gone a certain distance from it's origin
  1306.                     temp_x1# = bullets(i,0) - bullets(i,6) ;origin x on the right
  1307.                     temp_y1# = bullets(i,1) - bullets(i,7) ;origin y on the top
  1308.                     temp_x2# = bullets(i,6) - bullets(i,0) ;origin x on the left
  1309.                     temp_y2# = bullets(i,7) - bullets(i,1) ;origin y on the bottom
  1310.  
  1311.                     ;wraps distances around the map extremities
  1312.                     If temp_x1# < 0 Then
  1313.                         temp_x1# = temp_x1# + GAME_AREA_X
  1314.                     End If
  1315.                     If temp_x1# > GAME_AREA_X Then
  1316.                         temp_x1# = temp_x1# - GAME_AREA_X
  1317.                     End If
  1318.                     If temp_y1# < 0 Then
  1319.                         temp_y1# = temp_y1# + GAME_AREA_Y
  1320.                     End If
  1321.                     If temp_x1# > GAME_AREA_X Then
  1322.                         temp_y1# = temp_y1# - GAME_AREA_Y
  1323.                     End If
  1324.                     If temp_x2# < 0 Then
  1325.                         temp_x2# = temp_x2# + GAME_AREA_X
  1326.                     End If
  1327.                     If temp_x2# > GAME_AREA_X Then
  1328.                         temp_x2# = temp_x2# - GAME_AREA_X
  1329.                     End If
  1330.                     If temp_y2# < 0 Then
  1331.                         temp_y2# = temp_y2# + GAME_AREA_Y
  1332.                     End If
  1333.                     If temp_x2# > GAME_AREA_X Then
  1334.                         temp_y2# = temp_y2# - GAME_AREA_Y
  1335.                     End If
  1336.                     
  1337.                     ;calculates the shortest distance
  1338.                     If Abs(temp_x1#) < Abs(temp_x2#) Then
  1339.                         temp_x# = Abs(temp_x1#)
  1340.                     Else
  1341.                         temp_x# = Abs(temp_x2#)
  1342.                     End If
  1343.                     If Abs(temp_y1#) < Abs(temp_y2#) Then
  1344.                         temp_y# = Abs(temp_y1#)
  1345.                     Else
  1346.                         temp_y# = Abs(temp_y2#)
  1347.                     End If
  1348.                     
  1349.                     ;back to PYTHAGORAS to work out the "As the crow flies" distance from the bullet's original starting point
  1350.                     temp_x# = Abs(temp_x# / 200)
  1351.                     temp_y# = Abs(temp_y# / 200)
  1352.                     temp_hyp# = (temp_x#*temp_x#) + (temp_y#*temp_y#)
  1353.                     temp_hyp# = Sqr(temp_hyp#)
  1354.  
  1355.                     ;if the bullet has travelled "5" units from it's starting point, then..
  1356.                     If temp_hyp# > 5 Then
  1357.                         bullets(i,4) = 0    ;turn the bullet off
  1358.                     End If
  1359.                 End If
  1360.             Next    ;end of bullet coordinate repositioning loop
  1361.             
  1362.             ;this is the player's bullet limiting code, which follows exactly the same logic as the "enemies" code, earlier
  1363.             If bulletlimiter > 0 Then
  1364.                 bulletlimiter = bulletlimiter + 1
  1365.                 If bulletlimiter = 10 Then ;value essentially sets the fire-rate (the lower the number, the faster the fire rate!)
  1366.                     bulletlimiter = 0
  1367.                 End If
  1368.             End If
  1369.             
  1370.             ;calculate player explosions, using the "one frame advance every two screen updates" idea from before
  1371.             If player_explosion_frame > 0 Then
  1372.                 player_explosion_frame = player_explosion_frame + .5
  1373.                 If player_explosion_frame > 26 Then
  1374.                     player_explosion_frame = 26
  1375.                 End If
  1376.             End If
  1377.             
  1378.             ;this bit of code is fired when the player dies (gameovercounter is set to 1)
  1379.             ;and acts exactly the same as "menu_frame", in that it allows us to flash the words "GAME OVER" on and off!
  1380.             If gameovercounter > 0 Then
  1381.                 PLAYER_SPEED = PLAYER_SPEED - INCR_SLOW        ;slow the player speed gradually to 0 when the game ends
  1382.                 If PLAYER_SPEED <= 0 Then                    ;a nice "That's the end for you" statement if you die in mid-battle!
  1383.                     PLAYER_SPEED = 0
  1384.                 End If
  1385.                 gameovercounter = gameovercounter + 1
  1386.                 If gameovercounter = 25 Then
  1387.                     gameovercounter = 1
  1388.                     If gameoverstat = 1 Then
  1389.                         gameoverstat = 0
  1390.                     Else
  1391.                         gameoverstat = 1
  1392.                     End If
  1393.                 End If
  1394.             Else
  1395.                 PLAYER_SCORE = PLAYER_SCORE + 1        ;if the game is in progress still, then increase the PLAYER_SCORE by 1 every screen update
  1396.                                                     ;this acts as a kind of survival bonus for the more defensive player
  1397.             End If
  1398.             
  1399.             ;here's that copied code again, which turns 231 into "0000231", this time
  1400.             ;using PLAYER_SCORE and HI_SCORE as opposed to LAST_SCORE
  1401.             If PLAYER_SCORE < 10 Then
  1402.                 PLAYER_SCORE_STR = "000000"+Str(PLAYER_SCORE)
  1403.             ElseIf PLAYER_SCORE >=10 And PLAYER_SCORE < 100 Then
  1404.                 PLAYER_SCORE_STR = "00000"+Str(PLAYER_SCORE)
  1405.             ElseIf PLAYER_SCORE >=100 And PLAYER_SCORE < 1000 Then
  1406.                 PLAYER_SCORE_STR = "0000"+Str(PLAYER_SCORE)
  1407.             ElseIf PLAYER_SCORE >=1000 And PLAYER_SCORE < 10000 Then
  1408.                 PLAYER_SCORE_STR = "000"+Str(PLAYER_SCORE)
  1409.             ElseIf PLAYER_SCORE >=10000 And PLAYER_SCORE < 100000 Then
  1410.                 PLAYER_SCORE_STR = "00"+Str(PLAYER_SCORE)
  1411.             ElseIf PLAYER_SCORE >=100000 And PLAYER_SCORE < 1000000 Then
  1412.                 PLAYER_SCORE_STR = "0"+Str(PLAYER_SCORE)
  1413.             ElseIf PLAYER_SCORE >=100000 And PLAYER_SCORE < 10000000 Then
  1414.                 PLAYER_SCORE_STR = Str(PLAYER_SCORE)
  1415.             Else
  1416.                 PLAYER_SCORE_STR = "9999999"
  1417.             End If
  1418.             If PLAYER_SCORE >= HI_SCORE Then
  1419.                 HI_SCORE = PLAYER_SCORE
  1420.                 If HI_SCORE < 10 Then
  1421.                     HI_SCORE_STR = "000000"+Str(HI_SCORE)
  1422.                 ElseIf HI_SCORE >=10 And HI_SCORE < 100 Then
  1423.                     HI_SCORE_STR = "00000"+Str(HI_SCORE)
  1424.                 ElseIf HI_SCORE >=100 And HI_SCORE < 1000 Then
  1425.                     HI_SCORE_STR = "0000"+Str(HI_SCORE)
  1426.                 ElseIf HI_SCORE >=1000 And HI_SCORE < 10000 Then
  1427.                     HI_SCORE_STR = "000"+Str(HI_SCORE)
  1428.                 ElseIf HI_SCORE >=10000 And HI_SCORE < 100000 Then
  1429.                     HI_SCORE_STR = "00"+Str(HI_SCORE)
  1430.                 ElseIf HI_SCORE >=100000 And HI_SCORE < 1000000 Then
  1431.                     HI_SCORE_STR = "0"+Str(HI_SCORE)
  1432.                 ElseIf HI_SCORE >=100000 And HI_SCORE < 10000000 Then
  1433.                     HI_SCORE_STR = Str(HI_SCORE)
  1434.                 Else
  1435.                     HI_SCORE_STR = "9999999"
  1436.                 End If
  1437.             End If
  1438.         End If ;end of "IF FLAG_PAUSE = 0" IF Statement
  1439.         
  1440.         ;this flashes the "PAUSED" caption on and off when needs be!
  1441.         game_pause_frame = game_pause_frame + 1
  1442.         If game_pause_frame = 25 Then
  1443.             game_pause_frame = 1
  1444.             game_accept_pause = 1
  1445.             If game_pause_stat = 1 Then
  1446.                 game_pause_stat = 0
  1447.             Else
  1448.                 game_pause_stat = 1
  1449.             End If
  1450.         End If
  1451.  
  1452.     Next    ;end of the "for i = 1 to frames" FOR loop
  1453.     
  1454.     game_draw_update()    ;finally, draw all the pictures on the screen, based on their (possibly) new positions.
  1455. End Function
  1456.  
  1457. ;this function draws the game graphics in their freshly calculated positions
  1458. Function game_draw_update()
  1459.     SetBuffer BackBuffer()    ;draw all of the following to the backbuffer
  1460.     ClsColor 0,0,0            ;changes the CLearScreen colour to black (0,0,0)
  1461.     TileImage game_background,0,0    ;This acts as a CLear Screen, even if the Resolution is set bigger than "game_background"'s image size
  1462.     If starson=1 Then        ;draw all of the stars using their correct pictures, at the correct x and y positions
  1463.         For star.stars=Each stars ;(for each star in type 'stars' do the following..)
  1464.             DrawImage game_stars(star\depth),star\x,star\y    ;using the depth property of "stars" as the Array position
  1465.         Next
  1466.     End If
  1467.     
  1468.         ;this FOR Type loop draws all the versions of "icons" at their screen-position - relative to the PLAYER coordinates
  1469.         ;in the current animation frame. It also checks for the non-transparent areas of the ICON image touching the non-
  1470.         ;transparent areas of the PLAYER image and updates the PLAYER's relavent energy-level values.
  1471.         For icon.icons=Each icons
  1472.         
  1473.             ;this line draws the relavant icon image at coordinates "x" and "y" on (or off) the screen
  1474.             ;the correct icon image is chosen using the "icons"'s style as it's array position
  1475.             ;the x and y coordinates are worked out by subtracting the PLAYER's current position from the "icons"'s current position
  1476.             ;notice that we're using the same style of "SCREEN_WIDTH\2 - Half the ImageWidth of the Image" idea from the
  1477.             ;"menu_draw_update()" code?
  1478.             DrawImage game_icons(icon\style), (((SCREEN_WIDTH/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_X - icon\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_Y - icon\y)),Int(icon\frame)
  1479.  
  1480.             ;this line uses the command "ImagesCollide" to place a value in the variable "checkcol" which we didn't declare as a Global
  1481.             ;variable earlier. This is because it is only used once and then discarded.
  1482.             ;Images collide requires the following parameters (information):
  1483.             ;1. image1 name
  1484.             ;2. image1 x position
  1485.             ;3. image1 y position
  1486.             ;4. image1 animation frame number
  1487.             ;5. image2 name
  1488.             ;6. image2 x position
  1489.             ;7. image2 y position
  1490.             ;8. image2 animation frame number
  1491.             ;if the two images collide (at least one non-transparent pixel from each image is touching eachother) then
  1492.             ;"checkcol" will equal 1, otherwise it will equal 0 (no non-transparent pixels were touching)
  1493.             checkcol = ImagesCollide(game_icons(icon\style), (((SCREEN_WIDTH/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_X - icon\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_Y - icon\y)),Int(icon\frame),game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame)
  1494.             
  1495.             ;this IF statement says what to do when the two images *have* collided (and the game is still in progress, i.e.: gameovercounter isn't 1)
  1496.             If checkcol=1 And gameovercounter = 0 Then
  1497.             
  1498.                 sound_icon_channel = PlaySound(sound_icon)    ;plays the "icon" sound on it's appropriate channel
  1499.  
  1500.                 Select icon\style    ;back to SELECT..CASE statements, "Which type of icon has the player just collected?"
  1501.                     Case 1
  1502.                         
  1503.                         PLAYER_BOOSTERS = PLAYER_BOOSTERS + BONUS_BOOSTERS    ;add some extra points to the PLAYER_BOOSTERS value..
  1504.                         If PLAYER_BOOSTERS > 192 Then                        ;and check that it isn't full
  1505.                             PLAYER_BOOSTERS = 192
  1506.                         End If
  1507.                     Case 2
  1508.                         PLAYER_SHIELD = PLAYER_SHIELD + BONUS_SHIELD        ;add some points to the PLAYER_SHIELD
  1509.                         If PLAYER_SHIELD > 192 Then    
  1510.                             PLAYER_SHIELD = 192
  1511.                         End If
  1512.                     Case 3
  1513.                         PLAYER_CLOAK = PLAYER_CLOAK + BONUS_CLOAK            ;add some points to the PLAYER_CLOAK
  1514.                         If PLAYER_CLOAK > 192 Then    
  1515.                             PLAYER_CLOAK = 192
  1516.                         End If
  1517.                     Case 4
  1518.                         PLAYER_JUMPS = PLAYER_JUMPS + 1            ;this gives the PLAYER and extra Hyperjump icon
  1519.                         If PLAYER_JUMPS > 5 Then                ;the maximum of which is 5, so cap the PLAYER_JUMPS value at 5
  1520.                             PLAYER_JUMPS = 5
  1521.                         End If
  1522.                 End Select
  1523.                 icon\x = Rnd(0,GAME_AREA_X)                            ;once collected, an icon just reappears at a random point on the map
  1524.                 icon\y = Rnd(0,GAME_AREA_Y)
  1525.                 PLAYER_SCORE = PLAYER_SCORE + SCORE_ICONCOLLECT        ;additionally, a player scores some points for collecting an icon
  1526.             End If
  1527.         Next    ;end of the "icons" FOR loop
  1528.     
  1529.         ;similarly, this Type FOR loop goes through each enemy, drawing it at it's new position (relative to the player)
  1530.         ;and checks for collisions with the player.
  1531.         For enemy.enemies=Each enemies
  1532.         
  1533.             ;this bit confirms what angle to draw each "enemies" at (which animation frame)
  1534.             temp_enemy1_frame = enemy\angle/5
  1535.             If temp_enemy1_frame >= 72 Then
  1536.                 temp_enemy1_frame = temp_enemy1_frame - 72
  1537.             End If
  1538.             If temp_enemy1_frame < 0 Then
  1539.                 temp_enemy1_frame = temp_enemy1_frame + 72
  1540.             End If
  1541.             
  1542.             ;as long as the enemy isn't dead (busy exploding), then draw the enemy at it's x,y position and
  1543.             ;check for collisions with the player.
  1544.             If enemy\exp_frame = 0 Then
  1545.             
  1546.                 ;exactly the same as the icons, relative to the player position. The fact that an enemy moves it's x and y position is irrelevant, because
  1547.                 ;it's new position was already worked out in the last function ("game_loop_update()")
  1548.                 DrawImage game_enemy1, (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),temp_enemy1_frame
  1549.  
  1550.                 ;the same collision detection as an "icons" occurs for each enemy colliding with the player
  1551.                 checkcol = ImagesCollide(game_enemy1, (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),temp_enemy1_frame,game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame)
  1552.  
  1553.                 If checkcol=1 And gameovercounter = 0 Then        ;if the two images have collided (this version of "enemies" and the PLAYER)
  1554.  
  1555.                     PLAYER_SHIELD = PLAYER_SHIELD - DAMAGE_ENEMY_BASH        ;subtract some points off the player's SHIELD
  1556.  
  1557.                     If PLAYER_SHIELD < 0 Then            ;if the player's shield is less than 0, then
  1558.  
  1559.                         PLAYER_SHIELD = 0                ;set the player's shield back to it's minimum value
  1560.                         gameovercounter = 1                ;set the "game is still in progress" variable to 1 (i.e.: the game isn't running anymore)
  1561.                                                         ;in a second, this will start a chain of reaction in "game_loop_update" which make's the player
  1562.                                                         ;image be replaced by the explosion, followed shortly by the "GAME OVER" caption
  1563.  
  1564.                         explosion1or2 = Rnd(0,100)                                    ;there are 2 explosion sound effects (for variation)
  1565.                                                                                     ;this line creates a random number between 0 and 100
  1566.                                                                                     ;(I could just have well have used 0 and 1 and got near
  1567.                                                                                     ;enought the same probability of explosion 1 or 2 variation)
  1568.                                                                                     
  1569.                         If explosion1or2 > 49 Then                                    ;if the random number was greater than 49, then..
  1570.                         
  1571.                             sound_explosion_channel = PlaySound(sound_explosion1)        ;play Explosion sound number 1 on the explosion channel
  1572.  
  1573.                         Else                                                        ;if the number was 49 or less, then..
  1574.  
  1575.                             sound_explosion_channel = PlaySound(sound_explosion2)        ;play Explosion sound number 1 on the explosion channel
  1576.                         End If
  1577.  
  1578.                         player_explosion_frame = 1        ;set the player_explosion_frame to 1 (which in game_loop_update() will start the explosion image sequence)
  1579.                     End If
  1580.                     
  1581.                     If ChannelPlaying(sound_collision_channel) = False Then        ;once again, because this sample will be triggered multiple times as an enemy image
  1582.                                                                                 ;passes through the player image (i.e.: the enemy really rammed you, as opposed to
  1583.                                                                                 ;just catching you), we must allow for the echoing sample overlap (that we last saw
  1584.                                                                                 ;when the player pressed the BOOST or CLOAK key in game_loop_update() )
  1585.                                                                                 
  1586.                                                                                 ;so, "As long as the sample isn't already playing.."
  1587.                         sound_collision_channel = PlaySound(sound_collision)    ;play the "Collision" sound on it's appropriate channel reference
  1588.                     End If
  1589.                     
  1590.                     enemy\energy = enemy\energy - DAMAGE_PLAYER_BASH    ;the enemy also suffers damage for this collision
  1591.                     PLAYER_SCORE = PLAYER_SCORE + SCORE_ENEMYCOLLIDE    ;and the player scores some points
  1592.  
  1593.                     If enemy\energy <= 0 Then                    ;check to see if the "enemies"'s energy is 0 or less and
  1594.                         enemy\energy = 0                        ;cap it at it's minimum value (0)
  1595.  
  1596.                         explosion1or2 = Rnd(0,100)                        ;work out which of the two explosion sounds we'll use..
  1597.                         If explosion1or2 > 49 Then
  1598.                             sound_explosion_channel = PlaySound(sound_explosion1)
  1599.                         Else
  1600.                             sound_explosion_channel = PlaySound(sound_explosion2)
  1601.                         End If
  1602.                         enemy\exp_frame = 1            ;set the "enemies" exp_frame to 1 (which in game_loop_update() will start the explosion image sequence for this
  1603.                                                     ;version of "enemies")
  1604.                     End If
  1605.                 End If
  1606.  
  1607.             Else    ;if this "enemies" *was* in the middle of exploding, then
  1608.             
  1609.                 ;there are 25 frames in the Explosion animation, so when the explosion frame reaches 26, we don't want to draw *anything* any more!
  1610.                 If enemy\exp_frame <= 25 Then
  1611.                 
  1612.                     ;draw frames 1 to 25 at the "enemies" (still moving) postion, but instead of altering the
  1613.                     ;draw position for the Enemy image width/height, we alter it for the Explosion image width/height)
  1614.                     DrawImage game_explosion,(((SCREEN_WIDTH/2)-ImageWidth(game_explosion)/2) - (PLAYER_X - enemy\x)),(((SCREEN_HEIGHT/2)-ImageHeight(game_explosion)/2) - (PLAYER_Y - enemy\y)),Int(enemy\exp_frame-1)
  1615.  
  1616.                 Else                            ;once the explosion has run to it's last frame (it will now be at enemy\frame = 26)..
  1617.  
  1618.                     enemy\x=Rnd(0,GAME_AREA_X)            ;randomize this "enemies"'s position on the map
  1619.                     enemy\y=Rnd(0,GAME_AREA_Y)
  1620.                     enemy\energy = 100                    ;give it it's energy back..
  1621.                     enemy\angle = Int(Rnd(0,72)) * 5
  1622.                     enemy\maxspeed = Rnd(20,40)            ;reset it's speed abilities
  1623.                     enemy\speed = 0                        ;start the new generation of this "enemies" in a static position (as if it's just hyperjumped in!)
  1624.                     enemy\style = 1
  1625.                     enemy\exp_frame = 0                    ;stop it exploding!
  1626.                     
  1627.                     enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)
  1628.                     enemy\dist_travelled = 0
  1629.                     enemy\gen=enemy\gen +1        ;remember before, I said that the enemy would be worth more points as it regenerated?
  1630.                                                 ;here it is! If this was the first time it had been killed, next time will be worth *TWICE* the points
  1631.                                                 ;if it was the 5th time it had been killed, next time it will be worth *SIX* times the points etc..
  1632.                                                 
  1633.                 End If
  1634.             End If        ;end of the "is this enemies exploding" IF statement
  1635.         Next    ;end of the "enemies" FOR loop
  1636.  
  1637.         ;now we'll do the same for all the bullets on (or off) the screen    
  1638.         For i = 0 To bulletnum-1    ;this cycles though the array from position 1 to the final bullet number in the array..
  1639.                                     ;we use "bulletnum - 1" because there are (for example) 600 possible bullets that are stored
  1640.                                     ;in an array as 0, 1, 2, 3 ... 596, 597, 598 and 599
  1641.         
  1642.             Select bullets(i,4)        ;whose bullet is it? remember when we originally DIMmed this Array, I said that 0 was off, 1 was a PLAYER bullet and 2 was an enemy bullet?
  1643.                 Case 1
  1644.                 
  1645.                     ;if it's a player bullet then..
  1646.                     ;draw this bullet at it's position, relative to the player, in it's current animation frame
  1647.                     DrawImage game_bullet_player,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5)
  1648.  
  1649.                     ;this checks for collisions with this bullet and all the enemies..
  1650.                     For enemy.enemies = Each enemies
  1651.                         If enemy\exp_frame = 0 Then        ;.. as long as an enemy isn't already exploding..
  1652.  
  1653.                             ;to get the x and y positions for each image, I have just copied and pasted their original DRAWIMAGE parameters into this statement
  1654.                             ;watch out more missing off brackets and values..                        
  1655.                             checkcol = ImagesCollide(game_enemy1, (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),temp_enemy1_frame,game_bullet_player,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5))
  1656.  
  1657.                             If checkcol = 1 And gameovercounter = 0 Then     ;if the bullet hit the enemy (and the game isn't over) then
  1658.                                 bullets(i,4) = 0                                            ;turn off the bullet (effectively makes it disappear!)
  1659.                                 enemy\energy = enemy\energy - DAMAGE_ENEMY_IS_SHOT                ;take off some points from the "enemies"'s shield
  1660.                                 PLAYER_SCORE = PLAYER_SCORE + enemy\gen*SCORE_ENEMY_IS_SHOT        ;give the player points for the shot, with the 
  1661.                                                                                                 ;"enemies"'s GENeration value as a multiplier!
  1662.  
  1663.                                 ricochet1or2 = Rnd(0,100)                                    ;similarly to explosions, there are two ricochet sounds
  1664.                                 If ricochet1or2 > 49 Then
  1665.                                     sound_bullethit_channel = PlaySound(sound_bullethit1)
  1666.                                 Else
  1667.                                     sound_bullethit_channel = PlaySound(sound_bullethit2)
  1668.                                 End If
  1669.                             End If
  1670.                             If enemy\energy <= 0 Then                    ;checks to see if we've just killed the enemy!
  1671.                                 enemy\energy = 0
  1672.                                 explosion1or2 = Rnd(0,100)                            ;if we have, then play 1 of the two explosion sound effects..
  1673.                                 If explosion1or2 > 49 Then
  1674.                                     sound_explosion_channel = PlaySound(sound_explosion1)
  1675.                                 Else
  1676.                                     sound_explosion_channel = PlaySound(sound_explosion2)
  1677.                                 End If
  1678.                                 enemy\exp_frame = 1                        ;starts off the enemy explosion chain reaction in "game_loop_update()"
  1679.                             End If
  1680.                         End If        ;end of the "is enemy already dead" IF statement
  1681.                     Next    ;end of checking through each "enemies" FOR loop
  1682.                         
  1683.                 Case 2
  1684.                 
  1685.                     ;if it's an enemy bullet then..
  1686.                     ;draw this bullet at it's position, relative to the player, in it's current animation frame
  1687.                     DrawImage game_bullet_enemy1,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5)
  1688.  
  1689.                     checkcol = ImagesCollide(game_bullet_enemy1,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5),game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame)
  1690.  
  1691.                     If checkcol = 1 And gameovercounter = 0 Then                    ;if the bullet hit the player, and the game isn't already over..
  1692.  
  1693.                         PLAYER_SHIELD = PLAYER_SHIELD - DAMAGE_PLAYER_IS_SHOT        ;subtract some points from the PLAYER's SHIELD
  1694.  
  1695.                         ricochet1or2 = Rnd(0,100)                                    ;play one of the two ricochet sound effects..
  1696.                         If ricochet1or2 > 49 Then
  1697.                             sound_bullethit_channel = PlaySound(sound_bullethit1)
  1698.                         Else
  1699.                             sound_bullethit_channel = PlaySound(sound_bullethit2)
  1700.                         End If
  1701.                         bullets(i,4) = 0                    ;turn the bullet off..
  1702.                     End If
  1703.  
  1704.                     If PLAYER_SHIELD < 0 Then        ;checks to see if the player's SHIELD is less than 0
  1705.                         PLAYER_SHIELD = 0                ;caps the shield at it's minimum (0)
  1706.  
  1707.                         gameovercounter = 1            ;sets the "the game is over" variable to 1
  1708.  
  1709.                         explosion1or2 = Rnd(0,100)                                    ;chooses and plays the sound effect for one of our two explosion noises
  1710.                         If explosion1or2 > 49 Then
  1711.                             sound_explosion_channel = PlaySound(sound_explosion1)
  1712.                         Else
  1713.                             sound_explosion_channel = PlaySound(sound_explosion2)
  1714.                         End If
  1715.                         player_explosion_frame = 1    ;starts the player explosion chain reaction back in "game_loop_update"
  1716.                     End If
  1717.             End Select
  1718.         Next    ;end of the "bullet drawing/collision detecting" FOR loop
  1719.  
  1720.     ;this section draws the frames of "animation" for the hyperjump, or - if we're not mid hyperjump - draws the regular player frames
  1721.     ;the hyperjump bits look quite complecated, but it's just x and y positions that are changing in relation to the value of "hypercount"
  1722.     If hypercount > 0 And hypercount < 100 Then
  1723.         If hypercount/2 = Int(hypercount/2) Then        ;if the value of "hypercount" is EVEN then..
  1724.                                                         ;draw these four pictures
  1725.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-hypercount,frame2
  1726.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+hypercount,frame4
  1727.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+hypercount,frame6
  1728.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-hypercount,frame8
  1729.  
  1730.         Else                                            ;otherwise, if the value of "hypercount" is ODD, then..
  1731.                                                         ;draw these four pictures..
  1732.                                                         ;this ODD/EVEN swapping results in our "flickery" effect, but you
  1733.                                                         ;can see the distinct 4 pictures if you PAUSE the game in the middle of a jump!
  1734.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(1.4*hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame7
  1735.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(1.4*hypercount),frame5
  1736.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(1.4*hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame3
  1737.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(1.4*hypercount),frame1
  1738.         End If
  1739.     ElseIf hypercount >= 100 And hypercount < 200 Then    ;between 0 and 100, the 8 "ships" move outwards from the middle..
  1740.                                                         ;after that, they converge back to the centre, using exactly the same code, but "200 - hypercount"
  1741.                                                         ;instead of "hypercount". It's a cheap effect that didn't cost me any more Paint Shop Pro time
  1742.                                                         ;and it looks quite cool! :)
  1743.         If hypercount/2 = Int(hypercount/2) Then
  1744.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(200-hypercount),frame2
  1745.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(200-hypercount),frame4
  1746.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(200-hypercount),frame6
  1747.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(200-hypercount),frame8
  1748.         Else
  1749.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(1.4*(200-hypercount)),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame7
  1750.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(1.4*(200-hypercount)),frame5
  1751.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(1.4*(200-hypercount)),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame3
  1752.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(1.4*(200-hypercount)),frame1
  1753.         End If
  1754.  
  1755.     Else            ;if, on the other hand, we're not mid-hyperjump, then we'll just be drawing the normal player frames..
  1756.     
  1757.         ;checks to see that the angle we want to draw the frame for is 0 to 71 (as 360 degrees is the same as 0 degrees!)
  1758.         game_player_frame = PLAYER_ANGLE/5
  1759.         If game_player_frame = 72 Then
  1760.             game_player_frame = 0
  1761.         End If
  1762.         
  1763.         ;as long as the player isn't busy exploding..
  1764.         If player_explosion_frame = 0 Then
  1765.  
  1766.             If cloakon = 0 Then        ;if the "cloaking device" is off, then draw the player every screen update..
  1767.                 DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame
  1768.  
  1769.             Else                    ;if the "cloaking device" is on, only draw the player when the "cloakon" number is EVEN..
  1770.                                     ;this is our flickering effect used again..
  1771.                 If cloakon/2 = Int(cloakon/2) Then
  1772.                     DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame
  1773.                 End If
  1774.             End If
  1775.         Else
  1776.                     ;if, on the other hand, the player *is* busy exploding, then..
  1777.                     
  1778.             If player_explosion_frame <= 25 Then        ;draw frames 1 to 25 of the explosion animation (in the player's position), taking into account
  1779.                                                         ;the Explosion image size, rather than the player image size..
  1780.                 DrawImage game_explosion,(SCREEN_WIDTH/2)-ImageWidth(game_explosion)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_explosion)/2,Int(player_explosion_frame-1)
  1781.             End If
  1782.         End If
  1783.     End If
  1784.     
  1785.     ;As we said before, the foremost pictures are drawn last in our Video collage.
  1786.     ;the following lines draw the "HUD" display stuff like the radar and power bars.
  1787.     ;All of the images are drawn in Paint Shop and then a Magenta pixel is drawn every-other pixel on the image,
  1788.     ;so that when drawn on-screen in the program, some of the pixels beneath the image can be seen, wherever
  1789.     ;there is one of these Magenta (which we made transparent earilier) pixels.
  1790.     ;this gives a cheap and fast version of Cemi-transparency that you'd probably get in a C++ version of the game.
  1791.     DrawImage game_radar,SCREEN_WIDTH-210,3
  1792.     DrawImage game_shields,SCREEN_WIDTH-210,223
  1793.  
  1794.     ;after drawing the "SHIELDS" box, we want to draw "how much" SHIELD the player has left.
  1795.     ;the "game_levels" image is 192 pixels by 20 pixels in size. Because the PLAYER_SHIELD value
  1796.     ;runs from 0 to 192 pixels, we can simply draw the first PLAYER_SHIELD value by 20 pixels from the
  1797.     ;full "game_levels" image.
  1798.     ;For example, if the player has 100 points of PLAYER_SHIELD left, then we would want to draw the first
  1799.     ;100*20 pixels from the left of the image. 
  1800.     ;The DRAWIMAGERECT(rectangle) command will do this for us! It requires the following parameters:
  1801.     ;Image name, X-coordinate on-screen, Y-coordinate on-screen,
  1802.     ;top left x and y coordinates on the "game_levels" image and bottom right x and y coordinates
  1803.     DrawImageRect game_levels,SCREEN_WIDTH-206,236,0,0,Int(PLAYER_SHIELD),20
  1804.  
  1805.     ;do the same for CLOAK and BOOSTERS display
  1806.     DrawImage game_cloak,SCREEN_WIDTH-210,273
  1807.     DrawImageRect game_levels,SCREEN_WIDTH-206,286,0,0,Int(PLAYER_CLOAK),20
  1808.     DrawImage game_boosters,SCREEN_WIDTH-210,323
  1809.     DrawImageRect game_levels,SCREEN_WIDTH-206,336,0,0,Int(PLAYER_BOOSTERS),20
  1810.     
  1811.         ;notice that by using a calculated x coordinate "SCREEN_WIDTH - value" in conjunction with a fixed
  1812.         ;y coordinate, we will have the HUD images at the same distance from the top right of the screen
  1813.         ;in any Graphics resolution we choose
  1814.     
  1815.     ;the JUMPS box is slightly different, because it is not a solid bar.
  1816.     ;it is actually 5 different prerendered images    
  1817.     DrawImage game_jumps,SCREEN_WIDTH-210,373
  1818.  
  1819.     If PLAYER_JUMPS >= 1 Then                                ;this line says that if the player has 1 or more JUMPS left
  1820.         DrawImage game_jumps_level(1),SCREEN_WIDTH-205,389    ;then draw the leftmost JUMP indicator (at the calculated position)
  1821.     End If
  1822.     If PLAYER_JUMPS >= 2 Then                                ;if the player has 2 or more jumps left then draw
  1823.         DrawImage game_jumps_level(2),SCREEN_WIDTH-166,389    ;the second JUMP indicator. Obviously, if the player has 2 JUMPs
  1824.                                                             ;left then he will also have "1 or more jumps left", so the first
  1825.                                                             ;IF will fire as well as this one..
  1826.     End If
  1827.     If PLAYER_JUMPS >= 3 Then                                ;do the same for 3, 4 and 5 (which is the maximum number allowed)
  1828.         DrawImage game_jumps_level(3),SCREEN_WIDTH-127,389
  1829.     End If
  1830.     If PLAYER_JUMPS >= 4 Then
  1831.         DrawImage game_jumps_level(4),SCREEN_WIDTH-88,389
  1832.     End If
  1833.     If PLAYER_JUMPS >= 5 Then
  1834.         DrawImage game_jumps_level(5),SCREEN_WIDTH-49,389
  1835.     End If
  1836.     
  1837.     ;draw the SCORE and HISCORE boxes
  1838.     DrawImage game_score,10,SCREEN_HEIGHT-51
  1839.     DrawImage game_hiscore,230,SCREEN_HEIGHT-51
  1840.  
  1841.     ;remember this from "menu_draw_update()" where we built the HI and LAST SCORES out of the Strings
  1842.     ;by drawing the first character, then the second etc.. in a horizontally stepped increment?
  1843.     ;this is exactly the same code, but with slightly different coordinates and a different "font" AnimImage
  1844.     ;(which is "see through" like the blue boxes)
  1845.     For i = 1 To 7
  1846.         DrawImage game_scorefont,32+((i-1)*24),SCREEN_HEIGHT-35,Int(Mid(PLAYER_SCORE_STR,i,1))
  1847.         DrawImage game_scorefont,252+((i-1)*24),SCREEN_HEIGHT-35,Int(Mid(HI_SCORE_STR,i,1))
  1848.     Next
  1849.     
  1850.     ;this next bit of code draws the coloured dots on the radar
  1851.     ;by using their game map coordinates, at a ratio to the size of the radar box graphic
  1852.     For icon.icons=Each icons
  1853.         ;this draws each of the icons
  1854.         DrawImage game_icon_dot,((SCREEN_WIDTH-211)+icon\x/(GAME_AREA_X/200)),((9)+icon\y/(GAME_AREA_Y/200))
  1855.     Next
  1856.     For enemy.enemies=Each enemies
  1857.         ;this draws each of the enemies
  1858.         DrawImage game_enemy1_dot,((SCREEN_WIDTH-211)+enemy\x/(GAME_AREA_X/200)),((9)+enemy\y/(GAME_AREA_Y/200))
  1859.     Next
  1860.     
  1861.     ;this next bit draws the player's green dot on the radar
  1862.     If hypercount = 0 And cloakon=0 Then    ;if both the "hypercount" and "cloakon" features are inactive (i.e.: normal play)
  1863.         ;then permanently draw the player's radar dot
  1864.         DrawImage game_player_dot,((SCREEN_WIDTH-211)+PLAYER_X/(GAME_AREA_X/200)),((9)+PLAYER_Y/(GAME_AREA_Y/200))
  1865.  
  1866.     ElseIf hypercount = 0 And (cloakon/2 = Int(cloakon/2)) Then
  1867.         ;otherwise, if the cloakon value is EVEN, draw the dot (flickery effect again)
  1868.         ;but if the hypercount value isn't 0 (we're in the middle of a hyperjump) then don't do this..
  1869.         ;.. consequently, even though the player's position moves on the radar map during a hyperjump,
  1870.         ;and it affects the enemies, don't show this to the user!
  1871.         DrawImage game_player_dot,((SCREEN_WIDTH-211)+PLAYER_X/(GAME_AREA_X/200)),((9)+PLAYER_Y/(GAME_AREA_Y/200))
  1872.     End If
  1873.  
  1874.     ;if the game is paused (FLAG_PAUSE = 1) then draw the image when "game_pause_stat" = 1
  1875.     ;this gives us our flash on-off effect as used earlier in "menu_draw_update()"
  1876.     If FLAG_PAUSE = 1 And game_pause_stat = 1 Then
  1877.         DrawImage game_paused,SCREEN_WIDTH/2-ImageWidth(game_paused)/2,SCREEN_HEIGHT-((SCREEN_HEIGHT-350)/2+ImageHeight(game_paused)/2)
  1878.     End If
  1879.     
  1880.     ;exactly the same during a "GAME OVER" scenario
  1881.     If gameovercounter > 1 And gameoverstat = 1 Then
  1882.         DrawImage game_gameover,SCREEN_WIDTH/2-ImageWidth(game_gameover)/2,SCREEN_HEIGHT-((SCREEN_HEIGHT-350)/2+ImageHeight(game_gameover)/2)
  1883.     End If
  1884.  
  1885.     ;the following text will only be printed on the screen while the "FLAG_DEBUG" variable is set to 1 (F1, as I programmed it, on the main menu!)
  1886.     If FLAG_DEBUG = 1 Then
  1887.         ;the TEXT command writes a STRING of text onto the screen at the given coordinates in the currently set font
  1888.         ;as I haven't used the LoadFont or SetFont commands, this will just be Blitz' default font.
  1889.  
  1890.         Color 255,255,255                                    ;just in case, set the colo(u)r of the text to WHITE (255, 255, 255)
  1891.         Text 0,0,"PLAYER ANGLE = " + PLAYER_ANGLE                ;"Write the string 'PLAYER ANGLE = ' followed by the number held in PLAYER_ANGLE"
  1892.         Text 0,20,"PLAYER SPEED = " + PLAYER_SPEED
  1893.         Text 0,40,PLAYER_ANGLE + " / 5 = " + PLAYER_ANGLE/5
  1894.         Text 0,60,"SHIPFRAME = " + game_player_frame
  1895.         Text 0,80,"CO-ORDS = " + Int(PLAYER_X)
  1896.         Text 140,80," , " 
  1897.         Text 160,80,Int(PLAYER_Y)
  1898.         Text 0,100, "whichway = " + whichway
  1899.         Text 0,120, "SCORE = " + PLAYER_SCORE
  1900.         Text 0,140, "SCORESTR = " + PLAYER_SCORE_STR
  1901.  
  1902.         ;this debug code counts how many bullets are "active" in the array (their 'style' - bullets(i,4) is not 0
  1903.         ;this was useful for deciding how big the array needed to be for the game, i.e.: how many bullets array
  1904.         ;containers would be in use at any one time.
  1905.         ;in reality, during the game, this value rarely gets above 100 active bullets,
  1906.         ;but I kept the "available" bullets (bulletnum) at 500 anyway.
  1907.         
  1908.         ;if you needed better performance, then decreasing the value of "bulletnum" might increase the speed of the program!
  1909.         bulletcount = 0
  1910.         For i = 0 To bulletnum-1
  1911.             If bullets(i,4) > 0 Then
  1912.                 bulletcount = bulletcount + 1
  1913.             End If
  1914.         Next
  1915.         Text 0,160, "BULLETS = " + bulletcount
  1916.         Text 0,180, "P.E.F. = " + player_explosion_frame
  1917.         i = 0
  1918.         ;write some of the information about each of our enemies at the bottom of the screen.
  1919.         ;this was incredibly useful when working out the A.I. code, 'cos you could see in "words" what
  1920.         ;each enemy was doing, even when it wasn't on the screen!
  1921.         For enemy.enemies=Each enemies
  1922.             Text 20,((20*i)+380),i+1
  1923.             Text 40,((20*i)+380),enemy\angle
  1924.             Text 80,((20*i)+380),enemy\dest_angle
  1925.             Text 110,((20*i)+380),"y="+enemy\dest_opp
  1926.             Text 210,((20*i)+380),"x="+enemy\dest_adj
  1927.             Text 310,((20*i)+380),"hyp="+enemy\dest_hyp
  1928.             Text 430,((20*i)+380),enemy\rotate_angle
  1929.             Text 470,((20*i)+380),enemy\energy
  1930.             Text 510,((20*i)+380),enemy\exp_frame
  1931.             Text 610,((20*i)+380),enemy\gen
  1932.             Text (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),i+1
  1933.             i = i + 1
  1934.         Next
  1935.     End If
  1936.     
  1937.     ;just like in "menu_draw_update()", the user can press a key which just makes the value of "FLAG_SCREENSAVE" equal 1.
  1938.     ;when the code gets to here, it saves out the named Buffer as a BMP picture.
  1939.     If FLAG_SAVESCREEN=1 Then
  1940.         SaveBuffer (BackBuffer(),"CRGameScreen.bmp")
  1941.         FLAG_SAVESCREEN = 0
  1942.     End If 
  1943.     
  1944.     Flip                    ;as before in "menu_draw_update()", FLIP everything we've just drawn on the backbuffer and show it on the frontbuffer, i.e.: your monitor!!
  1945. End Function
  1946.  
  1947. ;a little function which randomizes the x and y coordinates of each version of the "stars" Type, plus it's "depth" property
  1948. Function game_stars_randomize()
  1949.     For star.stars=Each stars
  1950.         star\x=Rnd(-5,SCREEN_WIDTH)            ;create random x and y positions for all the stars
  1951.         star\y=Rnd(-5,SCREEN_HEIGHT)
  1952.         star\depth=Rnd(1,5)                    ;the depth of the stars results in our sexy parallex effect
  1953.     Next
  1954. End Function
  1955.  
  1956. ;an even littler function which just gives us random x and y coordinates for the player.
  1957. Function game_player_randomize()
  1958.     PLAYER_X = Rand(0,GAME_AREA_X)
  1959.     PLAYER_Y = Rand(0,GAME_AREA_Y)
  1960. End Function
  1961.  
  1962.  
  1963. ;This is the last function and it's MARVELLOUS! :)
  1964. ;This is the type of function that you should proactively *try* to write, because they're incredibly simple, yet incredibly effective
  1965. ;and they impress the girls, I can tell you... Um.. No.. That's a lie..
  1966.  
  1967. ;anyway the beauty of this function is that when you call it in the code above, you "feed" it some parameters.
  1968. ;this one is expecting an X Coordinate, a Y Coordinate, an Angle value, a Speed value and a Style value.
  1969. ;it doesn't care who or what they refer to, it just knows that it wants 5 numbers to work with.
  1970.  
  1971. ;So, when a player requires two bullets to be made, I just give it "PLAYER_X, PLAYER_Y, PLAYER_ANGLE,
  1972. ;PLAYER_SPEED and 1 (which just makes sure the correct bullet AnimImage is used!)
  1973.  
  1974. ;When an enemy needs a bullet, I just give it "Enemy X, Enemy Y, Enemy Angle, Enemy Speed, 2"
  1975.  
  1976. ;the createbullet() function does the rest and "produces" 2 bullets on the screen, starting at the end of the calling ship's laser.. BUT THAT'S ALL..
  1977. ;After the bullet has been created, its "life" is calculated in another part of the code (it's x and y coordinates are altered based on the original angle and speed
  1978. ;calculated in this function..) Enjoy
  1979.  
  1980. Function createbullet(x,y,angle,speed,style) ;creates 2 bullets starting on the end of a ship's lasers.
  1981.  
  1982.     ;there are "bulletnum" containers available in the "bullets()" array.
  1983.     ;if we've reached the maximum number of bullets, then the very first
  1984.     ;'bullet' will be overwritten with this new bullet. 
  1985.     ;We do this by wrapping "nextbullet" back to 0, when it reaches bulletnum
  1986.     If nextbullet = bulletnum-1 Then
  1987.         nextbullet = 0
  1988.     End If
  1989.     
  1990.     ;we want to create a bullet for the RIGHT laser of a ship
  1991.     ;by messing with the angleoffset value during debugging, I was able to come up with the
  1992.     ;correct values that looked right on screen (30 for this angle and 28 for the next calculation)
  1993.     angleoffset = angle - 30
  1994.     bullets(nextbullet,0) = x + 28*Cos(angleoffset)        ;this sets the x and y pixel offset from the ship's game coordinates
  1995.     bullets(nextbullet,1) = y + 28*Sin(angleoffset)        ;in this case 28*Cos/Sin of the angle offset
  1996.  
  1997.     ;these next bits are just setting the origin of the bullets, including it's start position, speed and angle
  1998.     ;this is so the bullets can fly independently of the PLAYER's ship's Angle and speed (unlike everything else in the game)
  1999.     bullets(nextbullet,2) = angle
  2000.     If speed <= 0 Then                        ;this bit essentially stops the player catching up to his bullets, or bullets flying backwards
  2001.         bullets(nextbullet,3) = 25            ;if the ship is still, or moving backwards, then a bullet fires off at a speed of 25
  2002.     Else
  2003.         bullets(nextbullet,3) = speed + 25    ;otherwise, if a ship is moving forwards, then the bullet flys off at a speed of 25, PLUS the ship's speed
  2004.     End If
  2005.  
  2006.     bullets(nextbullet,4) = style                    ;used to decide which bullet AnimImage should be used
  2007.     bullets(nextbullet,5) = 0                            ;used to keep track of the frame of animation a bullet is on
  2008.     bullets(nextbullet,6) = bullets(nextbullet,0)        ;used to know where a bullet began it's life in x and y coordinates
  2009.     bullets(nextbullet,7) = bullets(nextbullet,1)
  2010.     nextbullet = nextbullet+1                        ;we've successfully created a bullet (whose 'life' from now on will be calculated back
  2011.                                                     ;in "game_loop_update()", so now we move the "nextbullet" value on by 1
  2012.                                                     ;ready for creation of the next bullet!
  2013.  
  2014.  
  2015.  
  2016.     If nextbullet = bulletnum-1 Then                    ;exactly the same process, but with a 120 degree offset for the left hand laser
  2017.         nextbullet = 0
  2018.     End If
  2019.     angleoffset = angle - 150
  2020.     bullets(nextbullet,0) = x + 28*Cos(angleoffset)
  2021.     bullets(nextbullet,1) = y + 28*Sin(angleoffset)
  2022.     bullets(nextbullet,2) = angle
  2023.     If speed <= 0 Then
  2024.         bullets(nextbullet,3) = 25
  2025.     Else
  2026.         bullets(nextbullet,3) = speed + 25
  2027.     End If
  2028.     bullets(nextbullet,4) = style
  2029.     bullets(nextbullet,5) = 0
  2030.     bullets(nextbullet,6) = bullets(nextbullet,0)
  2031.     bullets(nextbullet,7) = bullets(nextbullet,1)
  2032.     nextbullet = nextbullet+1
  2033. End Function